我正在构建一个简单的Android应用程序,但我不断收到此异常NetworkOnMainThreadException。我已经研究了很多关于这个,我明白在android3.0(蜂窝)os及以上版本,它更严格,应该使用asyncTask(在后台线程上),我已经完成了我发现的所有内容,但仍然得到了这个异常,有人可以指导如何解决这个问题吗?
EditProductActivity.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();
}
}
}
对于布局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 Update 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 Delete 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>
这是调试错误堆栈:
线程[&lt; 1&gt; main](暂停(例外NetworkOnMainThreadException))
DefaultRequestDirector.execute(HttpHost,HttpRequest,HttpContext)行:531
DefaultHttpClient(AbstractHttpClient).execute(HttpHost,HttpRequest,HttpContext)行:555 DefaultHttpClient(AbstractHttpClient).execute(HttpUriRequest,HttpContext)行:487
DefaultHttpClient(AbstractHttpClient).execute(HttpUriRequest)行:465 JSONParser.makeHttpRequest(String,String,List)行:61
EditProductActivity $ GetProductDetails $ 1.run()行:120 Handler.handleCallback(消息)行:733
Handler.dispatchMessage(消息)行:95
Looper.loop()行:136 ActivityThread.main(String [])行:5017
Method.invokeNative(Object,Object [],Class,Class [],Class,int,boolean)line:not available [native method]
Method.invoke(Object,Object ...)行:515
ZygoteInit $ MethodAndArgsCaller.run()行:779
ZygoteInit.main(String [])行:595 NativeStart.main(String [])行:不可用[本机方法]
我认为我已经遵循了使用asyncTask的规则,使用onPreExecute(),onPostExecute()在后台执行任务。对不起,我是新手,非常感谢任何帮助。 Thx提前。
答案 0 :(得分:2)
我认为我已经遵循了使用asyncTask执行任务的规则 在背景上使用onPreExecute(),onPostExecute()。
不是因为在你的doInBackground
中你在UI线程上执行HTTP请求:
runOnUiThread(new Runnable() {
public void run() {
完全违背了使用异步任务的目的。
请删除runOnUiThread
,在后台执行您的请求,完成任务后,使用onPostExecute
更新您的字段。
答案 1 :(得分:0)
你的doInBackground方法正在调用runOnUIThread,这是无稽之谈。
您应该在doInBackground上进行后台工作,然后在onPostExecute中执行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, Integer> {
//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 = 0;
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 success;
}
//After completing background task dismiss the progress dialog
protected void onPostExecute(Integer 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
}
//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();
}
}
}
答案 2 :(得分:0)
您的doInBackground应该运行网络操作并将结果发布到onPostExecute,您可以在其中更新UI。
答案 3 :(得分:0)
doInBackground 不与主UI线程交互,并且您在 AsinTask 的 doinBackground 方法中提到了视图
还从 doInBackground
中删除 runOnUIThread还将这些内容放在 onPostExecute 方法
中 //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));