【问题标题】:Using AsyncTask but the app crushes [duplicate]使用 AsyncTask 但应用程序崩溃 [重复]
【发布时间】:2015-05-24 16:44:24
【问题描述】:

您可以看到 EditProductActivity 类内部的三个 AsyncTask 派生类。此类允许我在单击列表视图上的项目时获取产品详细信息,然后我可以编辑产品详细信息并保存或删除它。但是,当我单击该项目时,“R.layout.edit_product”布局不会出现并且应用程序停止。

logcat 说:android.os.NetworkOnMainThreadException

此外,我尝试评论“GetProductDetails extends AsyncTask”类,出现“R.layout.edit_product”布局但我无法获取产品详细信息,当我单击保存按钮时,应用程序再次崩溃。但是,删除功能有效。所以我认为这是前 2 个 AsyncTask 派生类的问题: GetProductDetails 和 SaveProductDetails 。我会尝试搜索有关 UI 线程的一些信息并尝试解决问题但失败了。有人可以帮忙吗?谢谢!

EditProductActivity.java

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://192.128.0.101/android_connect/get_product_details.php";

// url to update product
private static final String url_update_product = "http://192.128.0.101/android_connect/update_product.php";

// url to delete product
private static final String url_delete_product = "http://192.128.0.101/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();

    }

}
}

【问题讨论】:

  • 我是在使用来自 AsyncTask 后台线程的 UI 小部件,所以会出现问题吗?如果有,如何修改代码?
  • 亲爱的 Marcin Orlowski,我认为这是相关的,但完全不同。你为什么说我提出了一个重复的问题。它询问有关模拟器的问题,但我没有。

标签: php android android-asynctask onclick ui-thread


【解决方案1】:

问题在于那几行代码:

// 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);

你崩溃的原因是这段代码需要在其他线程中然后是 UI,只是在 doInBackground 中,它会工作

/**
     * Getting product details in background thread
     * */
    protected String doInBackground(String... params) {
                    int success = -1;
                    //Check for success tag
                    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
                        final JSONObject json = jsonParser.makeHttpRequest(
                                url_product_detials, "GET", params);

                        // check your log for json response
                        Log.d("Single Product Details", json.toString());
                        success = json.getInt(TAG_SUCCESS);
                        // json success tag
                    catch (JSONException e) {
                        e.printStackTrace();
                    }
                    final int finalSuccess = success;
                    // updating UI from Background Thread
                    runOnUiThread(new Runnable() {
                    public void run() {
                    if (finalSuccess == 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
                    }
                }
            }
        });

        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();
    }

【讨论】:

  • 感谢您的回复。我想知道如果我需要在 doInBackground 中移出代码,我应该将代码移到哪里?移动到 onPreExecute ?或 onPostExecute ?还是其他人?
  • 你只需要 if(success == 1) 等你的 UI 线程中的代码,你看,因为你只在那里使用 UI 小部件,剩下的就放出来UIThread 并最终成功,仅此而已
  • 对不起,我不能完全理解。你的意思是我应该删除代码?或者你介意告诉我正确的 doInBackground 方法应该是什么样子。非常感谢
  • 和 doInBackground 的 try{ } 中的所有代码都是相互关联的。我不能只修改 2 行代码,而是必须修改 try{ } 中的整个代码。不幸的是,我不知道
  • 我已经编辑了我的答案,抱歉格式化,但我希望你能明白这一点
猜你喜欢
  • 2018-12-19
  • 2023-03-21
  • 2019-09-08
  • 2018-10-07
  • 2012-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多