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){}