从后台线程

问题描述:

我的一些用户的更新适配器(也许50)是越来越崩溃,并显示以下错误:从后台线程

java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread.

如果我理解正确的话,它造成的一个的AsyncTask的doInBackground()调用adapter.clear();adapter.addAll(list);方法,我需要将它移动到onPostExecute()

问题是我不能再现该错误,所以我不能确定它是否修复。 StackOverflow上的一些类似问题似乎表明,仅仅将更新适配器更改为onPostExecute()方法并不能解决问题。

有谁知道我可以如何使每次在我的设备上发生此错误,以确保修复工作?我不明白它为什么在大多数情况下都能正常工作,但有时只会导致崩溃。

+0

你在某一个点做在你的列表中的任何插入?如果你是可以模拟的,看看会发生什么 – AndroidEnthusiast 2014-09-30 15:56:52

+0

当'mItemCount'不是零并且'mItemCount!= mAdapter.getCount()':[ListView时,抛出'layoutChildren()'中'ListView'的异常。的java(http://grepcode.com/file_/repo1.maven.org/maven2/org.robolectric/android-all/4.1.2_r1-robolectric-0/android/widget/ListView.java/?v=source) – 2014-09-30 16:01:20

+0

我在'doInBackground()'中用适配器做的唯一事情就是'adapter.clear();'和'adapter.addAll(list)'。到目前为止,我在所有设备上运行了数百次,而不是一次崩溃。 – TimSim 2014-09-30 16:02:31

简单的答案:你忘记打电话adapter.notifyDatasetChanged()

Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.

获取后台数据和onPostExecute()更新您的适配器,因为你永远不应该改变从后台线程适配器的内容。在UI线程上执行onPreExecute()onPostExecute()

+0

我在'onPostExecute()'中调用了该函数,该函数恰好在之后发生。但我更感兴趣的是重现这个错误。出于某种原因,它从来没有发生过我,所以它吱吱作响。 – TimSim 2014-09-30 16:00:05

要重现此问题,请在doInBackground()中更改适配器后尝试休眠。

例如:

@Override 
    protected Void doInBackground(Void... params) { 
    adapter.clear(); 
    try 
    { 
     Thread.sleep(5000); 
    } 
    catch(InterruptedException e){} 
    return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
    super.onPostExecute(result); 
    adapter.notifyDatasetChanged(); 
    } 
+0

仍然不会崩溃应用程序。 – TimSim 2014-09-30 17:59:30

+0

@TimSim是否会引发异常? – nyx 2014-09-30 18:01:57

你不应该调用任何UI事情doInBackground(..)方法。 只是调用它们在onPostExecute(..)以及onPreExecute(..)

例如

@Override 
    protected void onPostExecute(Void result) { 
    super.onPostExecute(result); 
    adapter.clear(); 
    } 

按照AsyncTask文档,在 “4个步骤” 的段落。

onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

试试这个..

runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        adapter.notifyDatasetChanged(); 
       } 
      });