Question

Im facing an issue on Android OS v4.x (particularly 4.0.3) with changing ListView's data while its scrolling - a crash happens saying that I'm trying to change data not from main UI thread, which is not true:

    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)]

The UI with ListView consists of 2 parts - the biggest one is the ListView and there is a special control at a bottom which triggers the data to change and this control is always visible. So user is able to start ListView scroll and while it scrolls user is able to use control which triggers the ListView's data change and this causes the crash. Of course a data change happens on the mainUI thread and I do use notifyDataSetChanged():

monthChanger.setOnMonthChangedListener(new OnMonthChangedListener() {

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

});

and the loadData() method just fills the corresponding ArrayList with other data:

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

so nothing really special here. The crash doesn't happen with AOS 2.3.5. Another way to get the same crash on AOS 4 is to tap the screen right after data was changed and ListView scrolls to the top.
What's wrong and how to avoid this bug?

Was it helpful?

Solution

The only workaround I found so far is to stop list scrolling before changing its data:

// 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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top