我们先来看一个简单的Android app例子(这里是一个商品存货清单项目),在Android程序中,我们可以访问(call)PHP脚本来执行简单的CRUD操作(创建,读取,更新,删除)。为了使你对它的体系结构有一个大概的了解,这里先说一下它是怎么工作的。首先你的Android项目访问(call)PHP脚本来执行一条数据操作,我们称它为“创建”。然后PHP脚本连接MySQL数据库来执行这个操作。这样,数据从Android程序流向PHP脚本,最终存储在MySQL数据库中。

好了,让我们来深入的看一下。

请注意:这里提供的代码只是为了使你能简单的连接Android项目和PHP,MySQL。你不能把它作为一个标准或者安全编程实践。在生产环境中,理想情况下你需要避免使用任何可能造成潜在注入漏洞的代码(比如MYSQL注入)。MYSQL注入是一个很大的话题,不可能用单独的一篇文章来说清楚,并且它也不在本文讨论的范围内,所以本文不以讨论。

1. 什么是WAMP Server

WAMP是Windows,Apache,MySQL和PHP,Perl,Python的简称。WAMP是一个一键安装的软件,它为开发PHP,MySQL Web应用程序提供一个环境。安装这款软件你相当于安装了Apache,MySQL和PHP。或者,你也可以使用XAMP


2. 安装和使用WAMP Server

你可以从http://www.wampserver.com/en/下载WAMP,安装完成之后,可以从开始->所有程序->WampServer->StartWampServer运行该程序。

在浏览器中输入http://localhost/来测试你的服务器是否安装成功。同样的,也可以打开http://localhost/phpmyadmin来检验phpmyadmin是否安装成功。

3. 创建和运行PHP项目

现在,你已经有一个能开发PHP和MYSQL项目的环境了。打开安装WAMP Server的文件夹(在我的电脑中,是C:\wamp\),打开www文件夹,为你的项目创建一个新的文件夹。你必须把项目中所有的文件放到这个文件夹中。

新建一个名为android_connect的文件夹,并新建一个php文件,命名为test.php,尝试输入一些简单的php代码(如下所示)。输入下面的代码后,打开http://localhost/android_connect/test.php,你会在浏览器中看到“Welcome,I am connecting Android to PHP,MySQL”(如果没有正确输入,请检查WAMP配置是否正确)

test.php

<?php 
echo"Welcome, I am connecting Android to PHP, MySQL"; 
?>
4. 创建MySQL数据库和表

在本教程中,我创建了一个简单的只有一张表的数据库。我会用这个表来执行一些示例操作。现在,请在浏览器中输入http://localhost/phpmyadmin/,并打开phpmyadmin。你可以用PhpMyAdmin工具创建数据库和表。

创建数据库和表:数据库名:androidhive,表:product

CREATE TABLE products(
pid int(11) primary key auto_increment,
name varchar(100) not null,
price decimal(10,2) not null,
description text,
created_at timestamp default now(),
updated_at timestamp
);
5. 用PHP连接MySQL数据库

现在,真正的服务器端编程开始了。新建一个PHP类来连接MYSQL数据库。这个类的主要功能是打开数据库连接和在不需要时关闭数据库连接。

新建两个文件db_config.php,db_connect.php

db_config.php--------存储数据库连接变量
db_connect.php-------连接数据库的类文件

db_config.php

<?php
 
/*
 * All database connection variables
 */
 
define('DB_USER', "root"); // db user
define('DB_PASSWORD', ""); // db password (mention your db password here)
define('DB_DATABASE', "androidhive"); // database name
define('DB_SERVER', "localhost"); // db server
?>

这里的DB_USER  DB_PASSWORD要换成自己数据库对应的用户名、密码

db_connect.php

 <?php
 
/**
 * A class file to connect to database
 */
class DB_CONNECT {
 
    // constructor
    function __construct() {
        // connecting to database
        $this->connect();
    }
 
    // destructor
    function __destruct() {
        // closing db connection
        $this->close();
    }
 
    /**
     * Function to connect with database
     */
    function connect() {
        // import database connection variables
        require_once __DIR__ . '/db_config.php';
 
        // Connecting to mysql database
        $con = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD) or die(mysql_error());
 
        // Selecing database
        $db = mysql_select_db(DB_DATABASE) or die(mysql_error()) or die(mysql_error());
 
        // returing connection cursor
        return $con;
    }
 
    /**
     * Function to close db connection
     */
    function close() {
        // closing db connection
        mysql_close();
    }
 
}
 
?>
怎么调用:当你想连接MySQl数据库或者执行某些操作时,可以这样使用db_connect.php

$db= new DB_CONNECT(); // creating class object(will open database connection)
6. 使用PHP执行基本CRUD操作

在这部分,我将讲述使用PHP对MySQL数据库执行基本CRUD(创建,读取,更新,删除)操作。

如果你是PHP和MySQL新手,我建议你可以先学习PHPSQL基础知识。

6. a)在MYSQL中新建一行(创建一行新的产品)

在你的PHP项目中新建一个php文件,命名为create_product.php,并输入以下代码。该文件主要实现在products表中插入一个新的产品。

在下面的代码我使用POST来读取产品数据并把他们存储在products表中。

最后我会输出一些JSON返回值,以便返回给客户端(Android项目)

create_product.php

<?php
 
/*
 * Following code will create a new product row
 * All product details are read from HTTP Post Request
 */
 
// array for JSON response
$response = array();
 
// check for required fields
if (isset($_POST['name']) && isset($_POST['price']) && isset($_POST['description'])) {
 
    $name = $_POST['name'];
    $price = $_POST['price'];
    $description = $_POST['description'];
 
    // include db connect class
    require_once __DIR__ . '/db_connect.php';
 
    // connecting to db
    $db = new DB_CONNECT();
 
    // mysql inserting a new row
    $result = mysql_query("INSERT INTO products(name, price, description) VALUES('$name', '$price', '$description')");
 
    // check if row inserted or not
    if ($result) {
        // successfully inserted into database
        $response["success"] = 1;
        $response["message"] = "Product successfully created.";
 
        // echoing JSON response
        echo json_encode($response);
    } else {
        // failed to insert row
        $response["success"] = 0;
        $response["message"] = "Oops! An error occurred.";
 
        // echoing JSON response
        echo json_encode($response);
    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";
 
    // echoing JSON response
    echo json_encode($response);
}
?>
对于上面的代码,JSON的返回值会是:

当POST 参数丢失

{ 
"success": 0, 
"message": "Required field(s) is missing"
}
当product成功创建

{ 
"success": 1, 
"message": "Product successfully created."
}
当插入数据时出现错误

{ 
"success": 0, 
"message": "Oops! An error occurred."
}

实际测试的时候,出现Required field(s) is missing php错误,我把$_POST换成$_GET就对了,对应的NewProductActivity也要换成GET方法

6. b)从MySQL中读取一行信息(读取产品详细信息)

创建一个新的php文件,命名为get_product_details.php,写入以下代码。

该文件通过传递产品id作为POST参数获得单个产品的详细信息

get_product_details.php

<?php
 
/*
 * Following code will get single product details
 * A product is identified by product id (pid)
 */
 
// array for JSON response
$response = array();
 
// include db connect class
require_once __DIR__ . '/db_connect.php';
 
// connecting to db
$db = new DB_CONNECT();
 
// check for post data
if (isset($_GET["pid"])) {
    $pid = $_GET['pid'];
 
    // get a product from products table
    $result = mysql_query("SELECT *FROM products WHERE pid = $pid");
 
    if (!empty($result)) {
        // check for empty result
        if (mysql_num_rows($result) > 0) {
 
            $result = mysql_fetch_array($result);
 
            $product = array();
            $product["pid"] = $result["pid"];
            $product["name"] = $result["name"];
            $product["price"] = $result["price"];
            $product["description"] = $result["description"];
            $product["created_at"] = $result["created_at"];
            $product["updated_at"] = $result["updated_at"];
            // success
            $response["success"] = 1;
 
            // user node
            $response["product"] = array();
 
            array_push($response["product"], $product);
 
            // echoing JSON response
            echo json_encode($response);
        } else {
            // no product found
            $response["success"] = 0;
            $response["message"] = "No product found";
 
            // echo no users JSON
            echo json_encode($response);
        }
    } else {
        // no product found
        $response["success"] = 0;
        $response["message"] = "No product found";
 
        // echo no users JSON
        echo json_encode($response);
    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";
 
    // echoing JSON response
    echo json_encode($response);
}
?>
The json response for the above file will be
When successfully getting product details
{ 
"success": 1, 
"product": [ 
{ 
"pid": "1", 
"name": "iPHone 4S", 
"price": "300.00", 
"description": "iPhone 4S white", 
"created_at": "2012-04-29 01:41:42", 
"updated_at": "0000-00-00 00:00:00"
} 
] 
}
When no product found with matched pid
{ 
"success": 0, 
"message": "No product found"
}
6. c)从MySQL读取所有行(读取所有产品信息)

我们需要用json数据在Android设备上显示所有的产品。

新建一个php文件,命名为get_all_products.php,写入以下代码。

get_all_products.php

<?php
 
/*
 * Following code will list all the products
 */
 
// array for JSON response
$response = array();
 
// include db connect class
require_once __DIR__ . '/db_connect.php';
 
// connecting to db
$db = new DB_CONNECT();
 
// get all products from products table
$result = mysql_query("SELECT *FROM products") or die(mysql_error());
 
// check for empty result
if (mysql_num_rows($result) > 0) {
    // looping through all results
    // products node
    $response["products"] = array();
 
    while ($row = mysql_fetch_array($result)) {
        // temp user array
        $product = array();
        $product["pid"] = $row["pid"];
        $product["name"] = $row["name"];
        $product["price"] = $row["price"];
        $product["created_at"] = $row["created_at"];
        $product["updated_at"] = $row["updated_at"];
 
        // push single product into final response array
        array_push($response["products"], $product);
    }
    // success
    $response["success"] = 1;
 
    // echoing JSON response
    echo json_encode($response);
} else {
    // no products found
    $response["success"] = 0;
    $response["message"] = "No products found";
 
    // echo no users JSON
    echo json_encode($response);
}
?>
And the JSON response for above code
Listing all Products
{ 
"products": [ 
{ 
"pid": "1", 
"name": "iPhone 4S", 
"price": "300.00", 
"created_at": "2012-04-29 02:04:02", 
"updated_at": "0000-00-00 00:00:00"
}, 
{ 
"pid": "2", 
"name": "Macbook Pro", 
"price": "600.00", 
"created_at": "2012-04-29 02:04:51", 
"updated_at": "0000-00-00 00:00:00"
}, 
{ 
"pid": "3", 
"name": "Macbook Air", 
"price": "800.00", 
"created_at": "2012-04-29 02:05:57", 
"updated_at": "0000-00-00 00:00:00"
}, 
{ 
"pid": "4", 
"name": "OS X Lion", 
"price": "100.00", 
"created_at": "2012-04-29 02:07:14", 
"updated_at": "0000-00-00 00:00:00"
} 
], 
"success": 1
}
When products not found
{ 
"success": 0, 
"message": "No products found"
}
6. d)在MySQL中更新某一行(更新产品详细信息)

新建一个php文件,命名为update_product.php。每一个产品通过pid标识。

update_product.php

<?php
 
/*
 * Following code will update a product information
 * A product is identified by product id (pid)
 */
 
// array for JSON response
$response = array();
 
// check for required fields
if (isset($_POST['pid']) && isset($_POST['name']) && isset($_POST['price']) && isset($_POST['description'])) {
 
    $pid = $_POST['pid'];
    $name = $_POST['name'];
    $price = $_POST['price'];
    $description = $_POST['description'];
 
    // include db connect class
    require_once __DIR__ . '/db_connect.php';
 
    // connecting to db
    $db = new DB_CONNECT();
 
    // mysql update row with matched pid
    $result = mysql_query("UPDATE products SET name = '$name', price = '$price', description = '$description' WHERE pid = $pid");
 
    // check if row inserted or not
    if ($result) {
        // successfully updated
        $response["success"] = 1;
        $response["message"] = "Product successfully updated.";
 
        // echoing JSON response
        echo json_encode($response);
    } else {
 
    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";
 
    // echoing JSON response
    echo json_encode($response);
}
?>
The json reponse of above code, when product is updated successfully
{ 
"success": 1, 
"message": "Product successfully updated."
}
6. e)在MySQL中删除某一行(删除一个产品)

新建一个php文件,命名为delete_product.php。该文件主要功能是从数据库中删除一个产品。

delete_product.php

<?php
 
/*
 * Following code will delete a product from table
 * A product is identified by product id (pid)
 */
 
// array for JSON response
$response = array();
 
// check for required fields
if (isset($_POST['pid'])) {
    $pid = $_POST['pid'];
 
    // include db connect class
    require_once __DIR__ . '/db_connect.php';
 
    // connecting to db
    $db = new DB_CONNECT();
 
    // mysql update row with matched pid
    $result = mysql_query("DELETE FROM products WHERE pid = $pid");
 
    // check if row deleted or not
    if (mysql_affected_rows() > 0) {
        // successfully updated
        $response["success"] = 1;
        $response["message"] = "Product successfully deleted";
 
        // echoing JSON response
        echo json_encode($response);
    } else {
        // no product found
        $response["success"] = 0;
        $response["message"] = "No product found";
 
        // echo no users JSON
        echo json_encode($response);
    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";
 
    // echoing JSON response
    echo json_encode($response);
}
?>
When product successfully deleted
{ 
"success": 1, 
"message": "Product successfully deleted"
}
When product not found
{ 
"success": 0, 
"message": "No product found"
}
到目前为止,我们为products表建立了一个简单的接口。服务器端编程已经完成了,接下来让我们开始真正的Android应用程序编程。

7. 新建一个Android应用程序

在Eclipse IDE中创建一个新项目,填写所需的细节信息。

1. 新建项目,在菜单中选择File->New->Android Project,把Activity类命名为MainScreenActivity

2. 打开AndroidManifest.xml,添加以下代码。我先在manifest文件中添加了所需的全部Activity类。同样需要添加INTERNET连接权限(非常重要)
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidhive"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk android:minSdkVersion="8" />
 
    <application
        android:configChanges="keyboardHidden|orientation"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
 
        <activity
            android:name=".MainScreenActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <!-- All Product Activity -->
        <activity
            android:name=".AllProductsActivity"
            android:label="All Products" >
        </activity>
 
        <!-- Add Product Activity -->
        <activity
            android:name=".NewProductActivity"
            android:label="Add New Product" >
        </activity>
 
        <!-- Edit Product Activity -->
        <activity
            android:name=".EditProductActivity"
            android:label="Edit Product" >
        </activity>
    </application>
 
    <!--  Internet Permissions -->
    <uses-permission android:name="android.permission.INTERNET" />
 
</manifest>
3. 在res->layout文件夹下新建一个xml文件,命名为mian_screen.xml。这个layout文件包含两个简单的按钮,通过这两个按钮可以查看所有产品和添加新产品。如下图所示

main_screen.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal">
 
    <!--  Sample Dashboard screen with Two buttons -->
    <!--  Button to view all products screen -->
    <Button android:id="@+id/btnViewProducts"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="View Products"
        android:layout_marginTop="25dip"/>
 
    <!--  Button to create a new product screen -->
    <Button android:id="@+id/btnCreateProduct"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Add New Products"
        android:layout_marginTop="25dip"/>
 
</LinearLayout>




4. 打开MainScreenActivity.java为main_screen.xml文件里的两个按钮添加点击事件

MainScreenActivity.java

package com.example.androidhive;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
 
public class MainScreenActivity extends Activity{
 
    Button btnViewProducts;
    Button btnNewProduct;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_screen);
 
        // Buttons
        btnViewProducts = (Button) findViewById(R.id.btnViewProducts);
        btnNewProduct = (Button) findViewById(R.id.btnCreateProduct);
 
        // view products click event
        btnViewProducts.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching All products Activity
                Intent i = new Intent(getApplicationContext(), AllProductsActivity.class);
                startActivity(i);
 
            }
        });
 
        // view products click event
        btnNewProduct.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // Launching create new product activity
                Intent i = new Intent(getApplicationContext(), NewProductActivity.class);
                startActivity(i);
 
            }
        });
    }
}
5. 在ListView中显示所有产品(读取)

现在我们需要一个Activity来以列表的形式显示所有产品。如我们所知,使用ListView需要两个xml文件,一个是列表布局,另一个是单个的列表项布局。在res->layout文件夹下新建两个xml文件:all_product.xml和list_item.xml
all_product.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <!-- Main ListView
         Always give id value as list(@android:id/list)
    -->
    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
 
</LinearLayout>
list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >
 
    <!-- Product id (pid) - will be HIDDEN - used to pass to other activity -->
    <TextView
        android:id="@+id/pid"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:visibility="gone" />
 
    <!-- Name Label -->
    <TextView
        android:id="@+id/name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingTop="6dip"
        android:paddingLeft="6dip"
        android:textSize="17dip"
        android:textStyle="bold" />
 
</LinearLayout>
6. 新建一个名为AllProductActivity.java的类文件。

在下面的代码中,

首先,在后台AsyncTask线程中发送一个请求给get_all_products.php

然后,从get_all_products.php获取JSON格式的数据,我为json转换了格式(parser),并使其显示在ListView中。

如果没有找到产品,会跳转到AddNewProductActivity

AllProductActivity.java

package com.example.androidhive;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
 
import org.apache.http.NameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
 
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
 
public class AllProductsActivity extends ListActivity {
 
    // Progress Dialog
    private ProgressDialog pDialog;
 
    // Creating JSON Parser object
    JSONParser jParser = new JSONParser();
 
    ArrayList<HashMap<String, String>> productsList;
 
    // url to get all products list
    private static String url_all_products = "http://api.androidhive.info/android_connect/get_all_products.php";
 
    // JSON Node names
    private static final String TAG_SUCCESS = "success";
    private static final String TAG_PRODUCTS = "products";
    private static final String TAG_PID = "pid";
    private static final String TAG_NAME = "name";
 
    // products JSONArray
    JSONArray products = null;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.all_products);
 
        // Hashmap for ListView
        productsList = new ArrayList<HashMap<String, String>>();
 
        // Loading products in Background Thread
        new LoadAllProducts().execute();
 
        // Get listview
        ListView lv = getListView();
 
        // on seleting single product
        // launching Edit Product Screen
        lv.setOnItemClickListener(new OnItemClickListener() {
 
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                // getting values from selected ListItem
                String pid = ((TextView) view.findViewById(R.id.pid)).getText()
                        .toString();
 
                // Starting new intent
                Intent in = new Intent(getApplicationContext(),
                        EditProductActivity.class);
                // sending pid to next activity
                in.putExtra(TAG_PID, pid);
 
                // starting new activity and expecting some response back
                startActivityForResult(in, 100);
            }
        });
 
    }
 
    // Response from Edit Product Activity
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // if result code 100
        if (resultCode == 100) {
            // if result code 100 is received
            // means user edited/deleted product
            // reload this screen again
            Intent intent = getIntent();
            finish();
            startActivity(intent);
        }
 
    }
 
    /**
     * Background Async Task to Load all product by making HTTP Request
     * */
    class LoadAllProducts extends AsyncTask<String, String, String> {
 
        /**
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(AllProductsActivity.this);
            pDialog.setMessage("Loading products. Please wait...");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(false);
            pDialog.show();
        }
 
        /**
         * getting All products from url
         * */
        protected String doInBackground(String... args) {
            // Building Parameters
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            // getting JSON string from URL
            JSONObject json = jParser.makeHttpRequest(url_all_products, "GET", params);
 
            // Check your log cat for JSON reponse
            Log.d("All Products: ", json.toString());
 
            try {
                // Checking for SUCCESS TAG
                int success = json.getInt(TAG_SUCCESS);
 
                if (success == 1) {
                    // products found
                    // Getting Array of Products
                    products = json.getJSONArray(TAG_PRODUCTS);
 
                    // looping through All Products
                    for (int i = 0; i < products.length(); i++) {
                        JSONObject c = products.getJSONObject(i);
 
                        // Storing each json item in variable
                        String id = c.getString(TAG_PID);
                        String name = c.getString(TAG_NAME);
 
                        // creating new HashMap
                        HashMap<String, String> map = new HashMap<String, String>();
 
                        // adding each child node to HashMap key => value
                        map.put(TAG_PID, id);
                        map.put(TAG_NAME, name);
 
                        // adding HashList to ArrayList
                        productsList.add(map);
                    }
                } else {
                    // no products found
                    // Launch Add New product Activity
                    Intent i = new Intent(getApplicationContext(),
                            NewProductActivity.class);
                    // Closing all previous activities
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    startActivity(i);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
 
            return null;
        }
 
        /**
         * After completing background task Dismiss the progress dialog
         * **/
        protected void onPostExecute(String file_url) {
            // dismiss the dialog after getting all products
            pDialog.dismiss();
            // updating UI from Background Thread
            runOnUiThread(new Runnable() {
                public void run() {
                    /**
                     * Updating parsed JSON data into ListView
                     * */
                    ListAdapter adapter = new SimpleAdapter(
                            AllProductsActivity.this, productsList,
                            R.layout.list_item, new String[] { TAG_PID,
                                    TAG_NAME},
                            new int[] { R.id.pid, R.id.name });
                    // updating listview
                    setListAdapter(adapter);
                }
            });
 
        }
 
    }
}

7. 添加一个新产品(写入)

创建一个新的view和activity来向MySQL数据库添加新产品。

新建一个简单的表单,创建提供输入产品名称,价格和描述的EditText

add_product.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    <!-- Name Label -->
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Product Name"
        android:paddingLeft="10dip"
        android:paddingRight="10dip"
        android:paddingTop="10dip"
        android:textSize="17dip"/>
 
    <!-- Input Name -->
    <EditText android:id="@+id/inputName"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dip"
        android:layout_marginBottom="15dip"
        android:singleLine="true"/>
 
    <!-- Price Label -->
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Price"
        android:paddingLeft="10dip"
        android:paddingRight="10dip"
        android:paddingTop="10dip"
        android:textSize="17dip"/>
 
    <!-- Input Price -->
    <EditText android:id="@+id/inputPrice"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dip"
        android:layout_marginBottom="15dip"
        android:singleLine="true"
        android:inputType="numberDecimal"/>
 
    <!-- Description Label -->
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Description"
        android:paddingLeft="10dip"
        android:paddingRight="10dip"
        android:paddingTop="10dip"
        android:textSize="17dip"/>
 
    <!-- Input description -->
    <EditText android:id="@+id/inputDesc"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dip"
        android:layout_marginBottom="15dip"
        android:lines="4"
        android:gravity="top"/>
 
    <!-- Button Create Product -->
    <Button android:id="@+id/btnCreateProduct"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Create Product"/>
 
</LinearLayout>

8. 新建一个Activity来处理向MySQL数据库插入新产品。

新建名为NewProductActivity.java的文件,输入以下代码。在下面的代码中

首先,从EditText获得用户输入的产品数据,格式化成基本参数格式

然后,向create_product.php发送请求,通过HTTP POST创建一个新的产品

最后,从create_product.php获取json返回值,如果success值为1,新得到的列表中就加入了新增的产品。

NewProductActivity.java

package com.example.androidhive;
 
import java.util.ArrayList;
import java.util.List;
 
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
 
public class NewProductActivity extends Activity {
 
    // Progress Dialog
    private ProgressDialog pDialog;
 
    JSONParser jsonParser = new JSONParser();
    EditText inputName;
    EditText inputPrice;
    EditText inputDesc;
 
    // url to create new product
    private static String url_create_product = "http://api.androidhive.info/android_connect/create_product.php";
 
    // JSON Node names
    private static final String TAG_SUCCESS = "success";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.add_product);
 
        // Edit Text
        inputName = (EditText) findViewById(R.id.inputName);
        inputPrice = (EditText) findViewById(R.id.inputPrice);
        inputDesc = (EditText) findViewById(R.id.inputDesc);
 
        // Create button
        Button btnCreateProduct = (Button) findViewById(R.id.btnCreateProduct);
 
        // button click event
        btnCreateProduct.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View view) {
                // creating new product in background thread
                new CreateNewProduct().execute();
            }
        });
    }
 
    /**
     * Background Async Task to Create new product
     * */
    class CreateNewProduct extends AsyncTask<String, String, String> {
 
        /**
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(NewProductActivity.this);
            pDialog.setMessage("Creating Product..");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(true);
            pDialog.show();
        }
 
        /**
         * Creating product
         * */
        protected String doInBackground(String... args) {
            String name = inputName.getText().toString();
            String price = inputPrice.getText().toString();
            String description = inputDesc.getText().toString();
 
            // Building Parameters
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("name", name));
            params.add(new BasicNameValuePair("price", price));
            params.add(new BasicNameValuePair("description", description));
 
            // getting JSON Object
            // Note that create product url accepts POST method
            JSONObject json = jsonParser.makeHttpRequest(url_create_product,
                    "POST", params);
 
            // check log cat fro response
            Log.d("Create Response", json.toString());
 
            // check for success tag
            try {
                int success = json.getInt(TAG_SUCCESS);
 
                if (success == 1) {
                    // successfully created product
                    Intent i = new Intent(getApplicationContext(), AllProductsActivity.class);
                    startActivity(i);
 
                    // closing this screen
                    finish();
                } else {
                    // failed to create product
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
 
            return null;
        }
 
        /**
         * After completing background task Dismiss the progress dialog
         * **/
        protected void onPostExecute(String file_url) {
            // dismiss the dialog once done
            pDialog.dismiss();
        }
 
    }
}
9. 读取,更新,删除一项产品

你稍加注意就会发现,在AllProductsActivity.java中,选中列表的某一项,会进入EditProductActivity.java。

接下来新建一个名为edit_product,xml的xml文件,创建类似create_product,xml的表单。

edit_product,xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    <!-- Name Label -->
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Product Name"
        android:paddingLeft="10dip"
        android:paddingRight="10dip"
        android:paddingTop="10dip"
        android:textSize="17dip"/>
 
    <!-- Input Name -->
    <EditText android:id="@+id/inputName"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dip"
        android:layout_marginBottom="15dip"
        android:singleLine="true"/>
 
    <!-- Price Label -->
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Price"
        android:paddingLeft="10dip"
        android:paddingRight="10dip"
        android:paddingTop="10dip"
        android:textSize="17dip"/>
 
    <!-- Input Price -->
    <EditText android:id="@+id/inputPrice"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dip"
        android:layout_marginBottom="15dip"
        android:singleLine="true"
        android:inputType="numberDecimal"/>
 
    <!-- Description Label -->
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Description"
        android:paddingLeft="10dip"
        android:paddingRight="10dip"
        android:paddingTop="10dip"
        android:textSize="17dip"/>
 
    <!-- Input description -->
    <EditText android:id="@+id/inputDesc"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dip"
        android:layout_marginBottom="15dip"
        android:lines="4"
        android:gravity="top"/>
 
    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <!-- Button Create Product -->
    <Button android:id="@+id/btnSave"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Save Changes"
        android:layout_weight="1"/>
 
    <!-- Button Create Product -->
    <Button android:id="@+id/btnDelete"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Delete"
        android:layout_weight="1"/>
    </LinearLayout>
 
</LinearLayout>
10. 对应edit_product.xml新建EditProductActivity.java,并输入下列代码。

在以下代码中:

首先,从intent中读取发送给ListView的产品id(pid)

然后,向get_product_details.php发送请求,获得json格式的产品详细信息,把它显示在EditText中。

然后,当产品信息显示在表单中后,如果用户点击保存按钮,会向update_product.php发送另一个HTTP请求,更新数据库中的产品信息

如果用户点击删除按钮,将会向delete_product.php发送请求,该产品慧聪MySQL数据库中删除,ListView刷新后显示新的产品列表。

EditProductActivity.java

package com.example.androidhive;
 
import java.util.ArrayList;
import java.util.List;
 
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
 
public class EditProductActivity extends Activity {
 
    EditText txtName;
    EditText txtPrice;
    EditText txtDesc;
    EditText txtCreatedAt;
    Button btnSave;
    Button btnDelete;
 
    String pid;
 
    // Progress Dialog
    private ProgressDialog pDialog;
 
    // JSON parser class
    JSONParser jsonParser = new JSONParser();
 
    // single product url
    private static final String url_product_detials = "http://api.androidhive.info/android_connect/get_product_details.php";
 
    // url to update product
    private static final String url_update_product = "http://api.androidhive.info/android_connect/update_product.php";
 
    // url to delete product
    private static final String url_delete_product = "http://api.androidhive.info/android_connect/delete_product.php";
 
    // JSON Node names
    private static final String TAG_SUCCESS = "success";
    private static final String TAG_PRODUCT = "product";
    private static final String TAG_PID = "pid";
    private static final String TAG_NAME = "name";
    private static final String TAG_PRICE = "price";
    private static final String TAG_DESCRIPTION = "description";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit_product);
 
        // save button
        btnSave = (Button) findViewById(R.id.btnSave);
        btnDelete = (Button) findViewById(R.id.btnDelete);
 
        // getting product details from intent
        Intent i = getIntent();
 
        // getting product id (pid) from intent
        pid = i.getStringExtra(TAG_PID);
 
        // Getting complete product details in background thread
        new GetProductDetails().execute();
 
        // save button click event
        btnSave.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View arg0) {
                // starting background task to update product
                new SaveProductDetails().execute();
            }
        });
 
        // Delete button click event
        btnDelete.setOnClickListener(new View.OnClickListener() {
 
            @Override
            public void onClick(View arg0) {
                // deleting product in background thread
                new DeleteProduct().execute();
            }
        });
 
    }
 
    /**
     * Background Async Task to Get complete product details
     * */
    class GetProductDetails extends AsyncTask<String, String, String> {
 
        /**
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(EditProductActivity.this);
            pDialog.setMessage("Loading product details. Please wait...");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(true);
            pDialog.show();
        }
 
        /**
         * Getting product details in background thread
         * */
        protected String doInBackground(String... params) {
 
            // updating UI from Background Thread
            runOnUiThread(new Runnable() {
                public void run() {
                    // Check for success tag
                    int success;
                    try {
                        // Building Parameters
                        List<NameValuePair> params = new ArrayList<NameValuePair>();
                        params.add(new BasicNameValuePair("pid", pid));
 
                        // getting product details by making HTTP request
                        // Note that product details url will use GET request
                        JSONObject json = jsonParser.makeHttpRequest(
                                url_product_detials, "GET", params);
 
                        // check your log for json response
                        Log.d("Single Product Details", json.toString());
 
                        // json success tag
                        success = json.getInt(TAG_SUCCESS);
                        if (success == 1) {
                            // successfully received product details
                            JSONArray productObj = json
                                    .getJSONArray(TAG_PRODUCT); // JSON Array
 
                            // get first product object from JSON Array
                            JSONObject product = productObj.getJSONObject(0);
 
                            // product with this pid found
                            // Edit Text
                            txtName = (EditText) findViewById(R.id.inputName);
                            txtPrice = (EditText) findViewById(R.id.inputPrice);
                            txtDesc = (EditText) findViewById(R.id.inputDesc);
 
                            // display product data in EditText
                            txtName.setText(product.getString(TAG_NAME));
                            txtPrice.setText(product.getString(TAG_PRICE));
                            txtDesc.setText(product.getString(TAG_DESCRIPTION));
 
                        }else{
                            // product with pid not found
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
 
            return null;
        }
 
        /**
         * After completing background task Dismiss the progress dialog
         * **/
        protected void onPostExecute(String file_url) {
            // dismiss the dialog once got all details
            pDialog.dismiss();
        }
    }
 
    /**
     * Background Async Task to  Save product Details
     * */
    class SaveProductDetails extends AsyncTask<String, String, String> {
 
        /**
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(EditProductActivity.this);
            pDialog.setMessage("Saving product ...");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(true);
            pDialog.show();
        }
 
        /**
         * Saving product
         * */
        protected String doInBackground(String... args) {
 
            // getting updated data from EditTexts
            String name = txtName.getText().toString();
            String price = txtPrice.getText().toString();
            String description = txtDesc.getText().toString();
 
            // Building Parameters
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair(TAG_PID, pid));
            params.add(new BasicNameValuePair(TAG_NAME, name));
            params.add(new BasicNameValuePair(TAG_PRICE, price));
            params.add(new BasicNameValuePair(TAG_DESCRIPTION, description));
 
            // sending modified data through http request
            // Notice that update product url accepts POST method
            JSONObject json = jsonParser.makeHttpRequest(url_update_product,
                    "POST", params);
 
            // check json success tag
            try {
                int success = json.getInt(TAG_SUCCESS);
 
                if (success == 1) {
                    // successfully updated
                    Intent i = getIntent();
                    // send result code 100 to notify about product update
                    setResult(100, i);
                    finish();
                } else {
                    // failed to update product
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
 
            return null;
        }
 
        /**
         * After completing background task Dismiss the progress dialog
         * **/
        protected void onPostExecute(String file_url) {
            // dismiss the dialog once product uupdated
            pDialog.dismiss();
        }
    }
 
    /*****************************************************************
     * Background Async Task to Delete Product
     * */
    class DeleteProduct extends AsyncTask<String, String, String> {
 
        /**
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(EditProductActivity.this);
            pDialog.setMessage("Deleting Product...");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(true);
            pDialog.show();
        }
 
        /**
         * Deleting product
         * */
        protected String doInBackground(String... args) {
 
            // Check for success tag
            int success;
            try {
                // Building Parameters
                List<NameValuePair> params = new ArrayList<NameValuePair>();
                params.add(new BasicNameValuePair("pid", pid));
 
                // getting product details by making HTTP request
                JSONObject json = jsonParser.makeHttpRequest(
                        url_delete_product, "POST", params);
 
                // check your log for json response
                Log.d("Delete Product", json.toString());
 
                // json success tag
                success = json.getInt(TAG_SUCCESS);
                if (success == 1) {
                    // product successfully deleted
                    // notify previous activity by sending code 100
                    Intent i = getIntent();
                    // send result code 100 to notify about product deletion
                    setResult(100, i);
                    finish();
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
 
            return null;
        }
 
        /**
         * After completing background task Dismiss the progress dialog
         * **/
        protected void onPostExecute(String file_url) {
            // dismiss the dialog once product deleted
            pDialog.dismiss();
 
        }
 
    }
}

11. JSONParser类

我用一个JSONParser类从URL获得JSON格式的数据。这个类支持两种http请求,GET和POST方法从URL获取JSON数据

JSONParser.java

package com.example.androidhive;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;
 
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
 
import android.util.Log;
 
public class JSONParser {
 
    static InputStream is = null;
    static JSONObject jObj = null;
    static String json = "";
 
    // constructor
    public JSONParser() {
 
    }
 
    // function get json from url
    // by making HTTP POST or GET mehtod
    public JSONObject makeHttpRequest(String url, String method,
            List<NameValuePair> params) {
 
        // Making HTTP request
        try {
 
            // check for request method
            if(method == "POST"){
                // request method is POST
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpPost httpPost = new HttpPost(url);
                httpPost.setEntity(new UrlEncodedFormEntity(params));
 
                HttpResponse httpResponse = httpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();
                is = httpEntity.getContent();
 
            }else if(method == "GET"){
                // request method is GET
                DefaultHttpClient httpClient = new DefaultHttpClient();
                String paramString = URLEncodedUtils.format(params, "utf-8");
                url += "?" + paramString;
                HttpGet httpGet = new HttpGet(url);
 
                HttpResponse httpResponse = httpClient.execute(httpGet);
                HttpEntity httpEntity = httpResponse.getEntity();
                is = httpEntity.getContent();
            }           
 
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            json = sb.toString();
        } catch (Exception e) {
            Log.e("Buffer Error", "Error converting result " + e.toString());
        }
 
        // try parse the string to a JSON object
        try {
            jObj = new JSONObject(json);
        } catch (JSONException e) {
            Log.e("JSON Parser", "Error parsing data " + e.toString());
        }
 
        // return JSON String
        return jObj;
 
    }
}
到这里,本教程就结束了。

运行你的代码,测试一下程序吧。你可能会遇到不少错误,经常使用LogCat来调试你的项目。

如果你不能解决那些错误,请在此留言。
原文链接:http://www.androidhive.info/2012/05/how-to-connect-android-with-php-mysql/

测试环境:WAMP: 2.4   Apache :2.4.4   PHP: 5.4.16

源码下载地址: http://download.csdn.net/detail/welovesunflower/7383361

Logo

更多推荐