java.lang.IllegalStateException错误

时间:2013-10-16 02:27:08

标签: java android android-asynctask android-adapter illegalstateexception

我正在调用ASyncTask来更新我的适配器,偶尔我在填充列表时遇到此运行时错误

  

E / AndroidRuntime(16197):java.lang.IllegalStateException:适配器的内容已更改,但ListView未收到通知。确保不从后台线程修改适配器的内容,而只是从UI线程修改。

从后台线程填充适配器是不是一个坏主意,如错误消息暗示的那样?

我在notifyDataSetChanged()中呼叫onPostExecute(),但是当我在onProgressUpdate()中呼叫时,我也会收到同样的错误。

这是我的ASyncTask。假设fetchOneItem()从项目列表中提取单个项目,填写名称/描述,然后转到下一次迭代中的下一个项目。

private class GetItems extends AsyncTask<Integer, Integer, Integer> {
  @Override
  protected void onPreExecute() {
    super.onPreExecute();
    pd = new ProgressDialog(context);
    pd.setTitle("Displaying...");
    pd.setMessage("Please wait.");
    pd.setCancelable(false);
    pd.setIndeterminate(true);
    pd.show();
    TextView myMsg = (TextView)findViewById(R.id.topMsg);
    myMsg.setText("Displaying items...");
  }

  protected Integer doInBackground(Integer... params) {
    // TODO Auto-generated method stub
    do {
      fetchOneItem(); // fetches 1 item
      myList.add(new Item(name, description));
      Log.i(TAG, "Adding " + name + ", " + desc + ", adapter size = " + myAdapter.getCount());
      publishProgress(i);
    } while (doneFetching != true);
    Log.i(TAG, "Completed loading, i =" + i);
    return i;
  }

  protected void onProgressUpdate(Integer... values) {
    TextView myMsg = (TextView)findViewById(R.id.topMsg);
    myMsg.setText("Displaying " + Integer.toString(values[0].intValue()) + " items");
  }

  @Override
  protected void onPostExecute(Integer numItems) {
    TextView myMsg = (TextView)findViewById(R.id.topMsg);
    myMsg.setText("Displayed " + numItems + " items");
    myAdapter.notifyDataSetChanged();
    allItemsLoaded = true;
    Log.i(TAG, "Adapter size = " + myAdapter.getCount());
    pd.dismiss();
  }
}

3 个答案:

答案 0 :(得分:0)

我可以看到您正试图“实时”更新列表视图吗?

好吧,我不知道怎么做,所以我建议你实现一个刷新按钮来调用这个AsyncTask。如果要向用户显示实际更新列表视图,则发送DialogProgress非常重要。希望它有所帮助!

答案 1 :(得分:0)

是的,你可以看到android不允许你这样做。如果要更新任何视图,则应在UI线程中执行此操作。但是你也应该永远不要在UI线程中使用慢速操作,例如android中不允许的网络通信。实际上你应该保持UI代码尽可能短,因为如果它需要太长时间,那么android会认为你的应用程序崩溃了。

编辑:我认为您正在使用ArrayAdapter,它会在您更新时通知更改。

所以你有两个选择:

使用您的ArrayAdapter,但在UI线程中更新它。

或者实现你自己的BaseAdapter子类,你做得对。

ArrayAdapter适用于简单情况,通常使用静态数据集。

答案 2 :(得分:0)

发帖迟到但可能会帮助遇到类似情况的人。

问题:您有一个长时间运行的操作,并希望将其带到后台线程。此外,操作完成后,您还要更新UI线程上的视图。

解决方案:

//spawn a new thread for background processing.
    new Thread(new Runnable() {
        @Override
        public void run() {
            //starting your background operation.
            //this is a network call.
            final Location location = BackendApi.builder().getSlaveLocation(mActivity.getApplicationContext(), "xyz", null);

            //now i want to update views on UI thread.
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    //this code will run on UI thread.
                    myView.setText("Latitude: " + location.getLatitude());
                }
            });
        }
    }).start();

在更新视图/适配器之前,请确保未销毁活动。