1

我在后台创建一个ListView的内容,并且当添加每个项目时,我更新ListView适配器。通常它工作正常,但有时候我得到此错误。奇怪的是,它在我的Galaxy S4迷你版中发生的次数要比我的HTC Sensation多出10倍。我不明白为什么会发生这种情况,因为我明确通过UI线程通知适配器。有什么想法吗 ?Android - 在AsyncTask中创建ListView内容导致随机崩溃

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. Make sure your adapter calls 
notifyDataSetChanged() when its content changes. [in ListView(2131100779, class 
util.TouchInterceptor) with Adapter(class com.bill.deuterh.ListActivity$ListAdapter)] 

的AsyncTask:

private class AsyncCaller extends AsyncTask<Void,Void,Void>{ 

    @Override 
    protected void onPostExecute(Void result) { 
     // TODO Auto-generated method stub 
     super.onPostExecute(result); 
     ListActivity.this.runOnUiThread(new Runnable(){ 
      @Override 
      public void run() { 
       findViewById(R.id.progress_bar).setVisibility(View.GONE); 
      } 
     }); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     // TODO Auto-generated method stub 

     for (int i=0;i<table.length;i++){ 
      if(isCancelled()){break;} 
      myList.add(createObject(table[i]))); 
      ListActivity.this.runOnUiThread(new Runnable(){ 
       @Override 
       public void run() { 
        ListAdapter.notifyDataSetChanged(); 
       } 
      }); 
     } 

     return null; 
    } 
} 

(如果它的事项,我投列表视图作为TouchInterceptor其是用于支持与拖放列表视图项的重排的改性谷歌类。)

+0

为什么不把'Listadapter.notifyDataSetChanged()'放到'onProgressUpdate()'中并通过'publishProgress'调用更新。人们,asynctask带有UI运行方法!使用它们。 'AsyncTask'功能强大,但不是以这种方式使用它 – Mike 2014-12-13 12:30:38

+0

在OnPostExecute中设置ListView适配器。 – 2014-12-13 12:30:43

回答

0

试试这个:如果一切正确设置。然后这段代码将立即显示你的doInBackground的每一个更新在listview =良好的用户体验!

private class AsyncCaller extends AsyncTask<Void,Void,Void>{ 

@Override 
protected void onPostExecute(Void result) { 
    // TODO Auto-generated method stub 
    super.onPostExecute(result); 
        findViewById(R.id.progress_bar).setVisibility(View.GONE); 
} 

@Override 
protected Void doInBackground(Void... params) { 
    // TODO Auto-generated method stub 

    for (int i=0;i<table.length;i++){ 
     if(isCancelled()){break;} 
     myList.add(createObject(table[i]))); 
     publishProgress(); 
    } 

    return null; 
} 

protected void onProgressUpdate(Void.. values) { 
ListAdapter.notifyDataSetChanged(); 
} 

}

OnPreExecute, onPostExecute and onProgressUpdate已经在UIThread运行。也许你不会以正确的方式执行asynctask。这就是为什么没有数据更新?

+0

这似乎是个伎俩。我打开了这个活动100次,并没有崩溃,所以我猜现在没关系。我不知道OnPreExecute,onPostExecute和onProgressUpdate在UI线程上执行。谢谢。 – Anonymous 2014-12-13 13:33:06

+0

@匿名欢迎!如果即使使用该更改,您的ListView也不会再膨胀,那么您将数据放入适配器的方式肯定有问题。再次,'UIMethods'是'AsyncTask'附带的强大功能之一!很高兴帮助你。快乐编码 – Mike 2014-12-13 13:35:39

+0

@匿名关于克里斯的评论最好是不要每循环都调用'publisProgress()'。这会导致你的屏幕冻结。如果您不希望用户等待整个内容,请以中等方式使用它。在整个'doInBackground()'中调用'publishProgress()'大约3-4次。我认为这是完美的! – Mike 2014-12-13 13:54:02

0

这应该只在onpostexecute结束时运行一次而不需要runonuithread。 ListAdapter.notifyDataSetChanged();

删除此:

ListActivity.this.runOnUiThread(new Runnable(){ 
     @Override 
     public void run() { 
      ListAdapter.notifyDataSetChanged(); 
     } 
    }); 

,并把这个:

@Override 
    protected void onPostExecute(Void result) { 
     // TODO Auto-generated method stub 
     super.onPostExecute(result); 
     findViewById(R.id.progress_bar).setVisibility(View.GONE); 
ListAdapter.notifyDataSetChanged(); 

    } 
+0

这是一个不好的解决方案。我想他希望立即在'listview'中显示新的数据。当一切都完成时不会在最后==用户体验不好! – Mike 2014-12-13 12:32:30

+0

notifyDataSetChanged不应该在循环中运行,因为它非常耗时。这是android开发人员创建此功能的唯一原因。 – chris 2014-12-13 13:42:26

+0

迈克看看那个循环,你认为需要多长时间才能完成?在冻结屏幕时,由于所有notfydatasetchanged函数都在低处理器上使用体验? – chris 2014-12-13 13:48:40

0

不要写任何代码在doInBackground(Void... params)其中涉及或更新UI。用于UI上的更新使用Async的onPostExecute(Void result)方法。 所以删除adatper的通知doInbackGround(Void... params){}