Android monkey causes adapter notification exception in android.widget.HeaderViewListAdapter

2.3k Views Asked by At

I am having the common problem:

java.lang.IllegalStateException: The content of the adapter has changed but List
View did not receive a notification. Make sure the content of your adapter is no
t modified from a background thread, but only from the UI thread. [in ListView(2
131427573, class android.widget.ListView) with Adapter(class android.widget.Head
erViewListAdapter)]

But the adapter is not my code, but in android.widget.HeaderViewListAdapter This is using Jellybean.

I read through the source code of HeaderViewListAdapter, ListAdapter and ListView. The IllegalStateException is thrown when the item count inListView is not equal to the count provided by the ListAdapter. In this case, the ListAdapter is the HeaderViewListAdapter. The HeaderViewListAdapters count is the count of the original ListAdapter passed by the client code, plus the size of the header and footer.

I traced through my code. All access to the ListView is on the UI thread, and is always followed by notifyDataSetChanged() to the adapter. I am using one footer.

This doesn't occur in normal usage. Is it due to Monkey? But how can Monkey modify my variables from other threads?

  • Update after more Monkey Testing

I removed the footer by removing the call to addFooterView(). Monkey no longer triggers the exception. Should I remove the call to addFooterView() at some point?

3

There are 3 best solutions below

2
On BEST ANSWER

You can try adding something like this to your ListView:

    @Override
protected void layoutChildren() {
    try {
        super.layoutChildren();
    } catch (IllegalStateException e) {
        ZLog.e(LOG, "This is not realy dangerous problem");
    }
}

If you add a headerview or a footerview ListView, and when you notifyDataSetChanged(), it will change the mItemCount to the item count of real adapter, but the right side will return the fake itemcount which has added the headercount and footercount.

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/widget/ListView.java?av=f#1538

3
On

I will explain my actual problem. If needed I will also attach some code.

The scenario is this: I've created an EndlessList attaching the list to a OnScrollListener. When I'm reaching the end of the List I start an AsyncTask (if there is data to load).

In the preExecute I add to the footer a view (spinner). In the doInBackground I fetch data from internet and in the onPostExecute I add data to the adapter and I remove the footer View (the loading spinner). You have to remove it because you cannot access to that view and put it on GONE.

In my code I never do a notifyDataSetChange because in the adapter(ArrayAdapter that I've cloned from JB source code), when you do an addAll it automatically do it

/**
 * Adds the specified Collection at the end of the array.
 *
 * @param collection The Collection to add at the end of the array.
 */
public void addAll(Collection<? extends T> collection) {
    synchronized (mLock) {
        if (mOriginalValues != null) {
            mOriginalValues.addAll(collection);
        } else {
            mObjects.addAll(collection);
        }
    }
    if (mNotifyOnChange) notifyDataSetChanged();
}

It works well but sometimes it crash with this damn error and I've no clue to solve it:

 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)]
    at android.widget.ListView.layoutChildren(ListView.java:1545)
    at android.widget.AbsListView.onTouchModeChanged(AbsListView.java:2239)
    at android.view.ViewTreeObserver.dispatchOnTouchModeChanged(ViewTreeObserver.java:591)
    at android.view.ViewRoot.ensureTouchModeLocally(ViewRoot.java:2122)
    at android.view.ViewRoot.ensureTouchMode(ViewRoot.java:2106)
    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2216)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1886)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3687)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
    at dalvik.system.NativeStart.main(Native Method)
2
On

I know its a late reply....but i just got this error recently .... I was using android-amazing-listview. And I am getting the same error ended with

(class android.widget.HeaderViewListAdapter)]).

Solution that work for me is->

I think this issues stems from the fact that getAdapter is returning the AmazingAdapter instead of the wrapped HeaderListViewAdapter causing a difference in count at times. I simply removed the getAdapter method from AmazingListView and haven't got the exception since.