CWAC EndlessAdapter Users: Upgrade, Please
If you have been using
I strongly encourage you
to upgrade to v1.2.1. There had been various reports of an
exception in the field, but only today was I given a reproducible
test case for it, and that bug should now be fixed.
If you are already on 1.x, there should be no code changes. Just update your Android library project, or grab a fresh JAR.
The error report was for:
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.
Lesson #1: Error messages may be misleading. In this case, the exception points out that this may be a threading problem. However, in my case, it turned out that this was not a threading problem, which led to a couple of lost hours of debugging.
Lesson #2: If you do something in an
getCount() returns, you need to call
In the case of
getCount() will return the
getCount() from the
Adapter that it wraps, or that value plus one.
The latter case is when
EndlessAdapter was told that there might
be more data, and so the extra item is a “pending view” used to
denote that there is data being loaded.
EndlessAdapter tracks whether or not there is data to be loaded
keepOnAppending. I dutifully made this be an
so it is a thread-safe value. However, what I did not take into account
was that toggling
getCount() to return a different value. Eventually,
notifyDataSetChanged() would be called, after which I was safe, but
there was a window of time in between there where manipulating the
list — such as tapping on a row — would trigger the
IllegalStateException really means is that the
ListView thinks there should be N rows, but the
Adapter is now
claiming that there are M rows, with M != N. These values are
synchronized via a call to
notifyDataSetChanged(), but if
getCount() changes before
notifyDataSetChanged() is called,
you have the window for potential problem.
My change is simply to call
notifyDataSetChanged() any time
I change the value of
keepOnAppending, thereby triggering
getCount() to change its return value.
In the field, you would see this problem when the
was told that we have no more data (toggling
false) but the user taps on a list item before
we get a chance to append the last chunk of data, which would trigger
Many thanks to jbenf for reporting the way to reproduce the error, which allowed me to make this fix.
Stuck on an Android problem? Subscribers have access to live office hours chats with Mark Murphy, to help you work through your challenges!