我是一个学习开发Android应用程序的初学者,我目前正在http://www.androidhive.info/2012/05/how-to-connect-android-with-php-mysql/上关注这个简单的教程,但在其中一个页面上我遇到了NetworkOnMainThreadException的问题,在我研究之后,android 3.0及以上版本在UI线程上执行http请求时会抛出异常,并且我必须使用AsyncTask。我一直在尝试修改代码以执行请求onPostExecute,但我一直在收到错误。
这是java代码:
package com.example.test;
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_details = "http://api.kerjaapa.com/android_connect/get_product_details.php";
//url to update product
private static final String url_update_product = "http://api.kerjaapa.com/android_connect/update_product.php";
//url to delete product
private static final String url_delete_product = "http://api.kerjaapa.com/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_details, "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 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 dialog
protected void onPostExecute(String file_url) {
//dismiss dialog
pDialog.dismiss();
}
}
//Background async task to delete product
class DeleteProduct extends AsyncTask<String, String, String> {
//Before starting, 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 dialog
protected void onPostExecute(String file_url) {
//dismiss dialog once finish
pDialog.dismiss();
}
}
}
问题出在GetProductDetails类中,它使用runOnUiThread(new Runnable(){public void run(),我试图擦除这些块并且应用程序会运行,但有时它会起作用,有时它会导致RunTimeException,并且应用程序会崩溃。我也尝试将变量成功传递给onPostExecute(),然后在onPostExecute()中,如果成功== 1,则显示JSON调用的结果,但在调整代码后,我不断收到错误并且无法#39;解决它。在像这样的项目中使用asyncTask的最佳做法是什么?
非常感谢任何指导。
提前谢谢
答案 0 :(得分:1)
请勿修改doInBackground
中的用户界面。
在这种情况下,我认为您应该将product
对象传递给您的onPostExecute
,它在UI线程上运行,您可以在其中修改UI:
//Background Async Task to Get Complete Product Details
class GetProductDetails extends AsyncTask<String, String, JSONObject> {
//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 JSONObject doInBackground(String... params) {
//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_details, "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);
return product;
} else {
//product with pid not found
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
//After completing background task dismiss the progress dialog
protected void onPostExecute(JSONObject product) {
//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));
//dismiss the dialog once got all details
pDialog.dismiss();
}
}
答案 1 :(得分:0)
我可以在您的代码中找到很多错误。最大的问题是,你确实需要解决的问题是你runOnUiThread(new Runnable() {
上不需要doInBackground()
,这主要是因为这种方法可以在后台运行,你可以在那里做你的要求。请求的结果必须传递给onPostExecute()
,此方法已在ui线程中运行。所以你应该更新那里的ui。
必须在onCreate()
中调用findViewById方法。试试这个并告诉我会发生什么。
答案 2 :(得分:0)
@Charas,
我调查您的代码并删除您的问题。您在后台调用“UI线程”并在UI上调用网络操作。所以你面对这类问题。请使用以下代码并享受编码....
package com.example.test;
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_details = "http://api.kerjaapa.com/android_connect/get_product_details.php";
//url to update product
private static final String url_update_product = "http://api.kerjaapa.com/android_connect/update_product.php";
//url to delete product
private static final String url_delete_product = "http://api.kerjaapa.com/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) {
//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_details, "GET", params);
//check your log for json response
Log.d("Single Product Details", json.toString());
//json success tag
success = json.getInt(TAG_SUCCESS);
} 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();
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
}
}
}
//Background Async Task to Save product details
class SaveProductDetails extends AsyncTask<String, String, String> {
//Before starting background thread, show 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);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
//After completing background task, dismiss dialog
protected void onPostExecute(String file_url) {
//dismiss dialog
pDialog.dismiss();
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
}
}
}
//Background async task to delete product
class DeleteProduct extends AsyncTask<String, String, String> {
//Before starting, 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);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
//After completing background task dismiss dialog
protected void onPostExecute(String file_url) {
//dismiss dialog once finish
pDialog.dismiss();
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();
}
}
}
}