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. [in ListView(16908298, class android.widget.ListView)
with Adapter(class android.widget.HeaderViewListAdapter)]
反覆檢查了一下所有使用 ListView, 確定都是在 UI Thread 改動, 但是卻一樣發生上面問題. 查看 Listview source code.
} else if (mItemCount != mAdapter.getCount()) { throw new 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. [in ListView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); }
裡面判斷 mItemCount 是否等於 mAdapter.getCount(), 而 mItemCount 在以下兩個地方取得:
1. setAdapter 的時候
2. onMeasure 的時候, 也就是 UI 有變動的時候.
而我所使用的 Adapter 都是從 ArrayAdapter 來. 在 add object 時, 都會通知一下資料變動, 理論上, ListView 也會收到通知,
所以跟著 mItemCount 會跟著修改, 但實際上 .... 一樣出現上面錯誤 !!!!
public void add(T object) { synchronized (mLock) { if (mOriginalValues != null) { mOriginalValues.add(object); } else { mObjects.add(object); } } if (mNotifyOnChange) notifyDataSetChanged(); }
Google 了半天, 最後我自己歸納以下結果, 當 setAdapter 後, 在大量新增 item 時, 有可能 ListView Upate 會跟不上 Adapter 的 Update.
所以當使用者捲動或者點擊時, 就有可能會出現這種狀況. (發生機率不高, 但從 Acra report, 我卻還滿常看到這 exception).
以下是我的解決方法, 到目前為止沒有在看到此 exception
import android.content.Context; import android.widget.ArrayAdapter; import java.util.List; public class MyArrayAdapterextends ArrayAdapter { private List mObjects; private int count = 0; private boolean mNotifyOnChange = true; public MyArrayAdapter(Context context, int textViewResourceId, List objects) { super(context, textViewResourceId, objects); mObjects = objects; count = objects.size(); } final public void beginTrans() { setNotifyOnChange(false); mNotifyOnChange = false; } final public void endTrans() { setNotifyOnChange(true); notifyDataSetChanged(); } @Override final public int getCount() { return count; } @Override final public void notifyDataSetChanged() { count = mObjects.size(); mNotifyOnChange = true; super.notifyDataSetChanged(); } @Override final public T getItem(int position) { if (position >= getCount()) { return null; } if (position >= mObjects.size()) { return null; } return super.getItem(position); } }
當要加入大量的 item 時, 則做以下動作.
1. call beginTrans
2. start to batch add items.
3. call endTrans
總算解決一個問題 :D
沒有留言:
張貼留言