只有创建视图层次结构的原始线程才能触及其视图突然错误

时间:2014-03-17 08:28:38

标签: android

最近,我将我的数据库从localhost移到了一个在线数据库中。我的localhost一切正常。我没有更改除url之外的任何代码。为什么我现在面对这个错误,因为它之前没有出现?

logcat的:

03-17 04:15:26.370: E/AndroidRuntime(804): FATAL EXCEPTION: AsyncTask #3
03-17 04:15:26.370: E/AndroidRuntime(804): java.lang.RuntimeException: An error occured while executing doInBackground()
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.os.AsyncTask$3.done(AsyncTask.java:299)
03-17 04:15:26.370: E/AndroidRuntime(804):  at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
03-17 04:15:26.370: E/AndroidRuntime(804):  at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
03-17 04:15:26.370: E/AndroidRuntime(804):  at java.util.concurrent.FutureTask.run(FutureTask.java:239)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
03-17 04:15:26.370: E/AndroidRuntime(804):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
03-17 04:15:26.370: E/AndroidRuntime(804):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
03-17 04:15:26.370: E/AndroidRuntime(804):  at java.lang.Thread.run(Thread.java:841)
03-17 04:15:26.370: E/AndroidRuntime(804): Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5908)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:869)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.view.ViewGroup.invalidateChild(ViewGroup.java:4253)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.view.View.invalidate(View.java:10482)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.TextView.invalidateRegion(TextView.java:4591)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.TextView.invalidateCursor(TextView.java:4534)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.TextView.spanChange(TextView.java:7412)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.TextView$ChangeWatcher.onSpanAdded(TextView.java:9103)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.text.SpannableStringBuilder.sendSpanAdded(SpannableStringBuilder.java:979)
03-17 04:15:26.370: E/AndroidRuntime(804):  at  android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:688)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:588)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.text.Selection.setSelection(Selection.java:76)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.text.Selection.setSelection(Selection.java:87)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.text.method.ArrowKeyMovementMethod.initialize(ArrowKeyMovementMethod.java:302)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.TextView.setText(TextView.java:3759)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.TextView.setText(TextView.java:3629)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.EditText.setText(EditText.java:80)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.widget.TextView.setText(TextView.java:3604)
03-17 04:15:26.370: E/AndroidRuntime(804):  at my.fyp.inticlassifieds.DisplayItemInfoEdit$GetProductDetails.doInBackground(DisplayItemInfoEdit.java:175)
03-17 04:15:26.370: E/AndroidRuntime(804):  at my.fyp.inticlassifieds.DisplayItemInfoEdit$GetProductDetails.doInBackground(DisplayItemInfoEdit.java:1)
03-17 04:15:26.370: E/AndroidRuntime(804):  at android.os.AsyncTask$2.call(AsyncTask.java:287)
03-17 04:15:26.370: E/AndroidRuntime(804):  at java.util.concurrent.FutureTask.run(FutureTask.java:234)
03-17 04:15:26.370: E/AndroidRuntime(804):  ... 4 more

类别:

public class DisplayItemInfoEdit extends Activity {

EditText txtName;
EditText txtPrice;
EditText txtDesc;
EditText txtCreatedAt;
Button btnSave;
Button btnCancel;
Spinner requeststatus;
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://10.0.2.2:8000/project/get_item_info.php";
private static final String url_product_detials = "http://inticlassifields.comze.com/phpscripts/get_item_info.php";

// url to update product
//private static final String url_update_product = "http://10.0.2.2:8000/project/update_item.php";
private static final String url_update_product = "http://inticlassifields.comze.com/phpscripts/update_item.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";
private static final String TAG_STATUS = "status";

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_req_info_edit);

    btnSave = (Button) findViewById(R.id.btnSave);
    btnCancel = (Button) findViewById(R.id.btnCancel);
    requeststatus = (Spinner) findViewById(R.id.reqstatusspinner);
    // Create an ArrayAdapter using the string array and a default spinner
    // layout
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.request_status,
            android.R.layout.simple_spinner_item);
    // Specify the layout to use when the list of choices appears
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    // Apply the adapter to the spinner
    requeststatus.setAdapter(adapter);

    // 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) {
            if(txtName.length()<2)
            {
                Toast.makeText(DisplayItemInfoEdit.this,"Please enter valid item name", Toast.LENGTH_LONG).show();
                return;
            }
             if(txtPrice.length()==0)
             {              
                Toast.makeText(DisplayItemInfoEdit.this,"Please enter item price", Toast.LENGTH_LONG).show();
                return;
             } 

            // starting background task to update product
            new SaveProductDetails().execute();
        }
    });

    // Cancel button click event
    btnCancel.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // return to main menu
            Intent i = new Intent();
            i.setClass(DisplayItemInfoEdit.this, MainMenu.class);
            startActivity(i);
        }
    });

}

/**
 * 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(DisplayItemInfoEdit.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... args) {
        // 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());
        try {
            // json success tag
            int success;
            success = json.getInt(TAG_SUCCESS);
            if (success == 1) {
                // successfully received product details
                JSONArray productObj = json.getJSONArray(TAG_PRODUCT); 

                // 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(DisplayItemInfoEdit.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();
        String status = requeststatus.getSelectedItem().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));
        params.add(new BasicNameValuePair(TAG_STATUS, status));

        // 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
                DisplayItemInfoEdit.this.runOnUiThread(new Runnable() {
                      public void run() {
                        Toast.makeText(DisplayItemInfoEdit.this,"Item updated", Toast.LENGTH_LONG).show();
                      }
                    });
                Intent i = new Intent();
                i.setClass(DisplayItemInfoEdit.this, MainMenu.class);
                startActivity(i);
            } 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 updated
        pDialog.dismiss();
    }
}
}

错误来自以下代码行:

txtName.setText(product.getString(TAG_NAME));
txtPrice.setText(product.getString(TAG_PRICE));
txtDesc.setText(product.getString(TAG_DESCRIPTION));

2 个答案:

答案 0 :(得分:0)

您无法从外部UI线程(mainthread)更改触摸Android UI工具包。因此,将以下行移至onPostExecute()api:

txtName.setText(product.getString(TAG_NAME));
txtPrice.setText(product.getString(TAG_PRICE));
txtDesc.setText(product.getString(TAG_DESCRIPTION));

doInBackground() api正在另一个线程中运行。

android开发者引用:

Andoid UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:

Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread

点击链接了解更多详情:

http://developer.android.com/guide/components/processes-and-threads.html

答案 1 :(得分:0)

正如Sushil所说,你无法修改UI线程中的android ui工具包。您可以移动代码或实现处理程序系统,以通知主线程修改您的edittext。 基本上,您只需要创建一个处理程序,通知您执行的操作:

txtName.setText(product.getString(TAG_NAME));
txtPrice.setText(product.getString(TAG_PRICE));
txtDesc.setText(product.getString(TAG_DESCRIPTION))