1

我在 Android OS v4.x(尤其是 4.0.3)上遇到了一个问题,即在滚动时更改 ListView 的数据 - 发生崩溃说我试图更改不是来自主 UI 线程的数据,这是不正确的:

    E/AndroidRuntime(2453): 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 mypackage.activity.MyListViewActivity$ListViewAdapter)]

带有 ListView 的 UI 由两部分组成——最大的一个是 ListView,底部有一个特殊的控件,可以触发数据更改,并且该控件始终可见。因此,用户能够启动 ListView 滚动,并且在滚动时用户能够使用触发 ListView 数据更改的控件,这会导致崩溃。当然,数据更改发生在 mainUI 线程上,我确实使用了 notifyDataSetChanged()

monthChanger.setOnMonthChangedListener(new OnMonthChangedListener() {

    @Override
    public void monthDidChange(int month) {
        currentMonth = month;
        loadData();
        listAdapter.notifyDataSetChanged();
    }

});

loadData() 方法只是用其他数据填充相应的 ArrayList:

    void loadData() {
        List<DataHolder> tempDataList = DataRetriever.getData(currentMonth);
        dataList.clear();
        dataList.addAll(tempDataList);
    }

所以这里没有什么特别的。AOS 2.3.5 不会发生崩溃。在 AOS 4 上获得相同崩溃的另一种方法是在数据更改并且 ListView 滚动到顶部后立即点击屏幕。
出了什么问题以及如何避免此错误?

4

1 回答 1

0

到目前为止,我发现的唯一解决方法是在更改其数据之前停止列表滚动:

// before changing the data of ListView's adapter
if (listView!=null){
    MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL, 0, 0, 0);
    listView.dispatchTouchEvent(me);
    me.recycle();
}
// now its safe to change data and call notifyDatasetChanged()
于 2013-12-19T17:25:04.317 回答