Re: [android-developers] IllegalStateException after ListView's adapter has changed

2010-04-07 Thread Jerry Fan
I have a fix for this. Just set the visibility of ur ListView to Gone during
update and back to visible after update. By doing so, u can avoid the
inconsistency of ur adapter and listView item count.

On Mon, Feb 22, 2010 at 3:31 PM, Jayesh Salvi  wrote:

> Hi,
>
> This is regarding the exception:  "java.lang.IllegalStateException: The
> content of the adapter has changed but ListView did not receive a
> notification." - seen on Android 1.6+
>
> This problem has been discussed in the past [1][2][3][4], and I have
> followed all the solutions suggested in those threads. However, few of my
> users still hit this crash. So I did some source code lookup and have some
> questions.
>
> Here is the description of what my app is doing:
>
> I use a ListView and populate it with an adapter. The adapter is a direct
> derivative of BaseAdapter. I populate the list progressively. As the items
> are downloaded from network they get added to the adapter. The fetching of
> items is done in doInBackground() and when they are ready to get added to
> the adapter I invoke publishProgress(), in the onProgressUpdate() method I
> add new items one-by-one to the adapter. As soon as I add the item to the
> adapter, I invoke notifyDataSetChanged().
>
> I believe this is as per the best practices that Android developers have
> suggested in above mentioned threads.
>
> Despite this I get crash reports with this exception. They are rare, but
> not as rare as ignorable. I myself have hit this crash on my phone/emulator
> only 1-2 times in last couple of months. The user reported crashes are
> roughly 1 to 3 per day (approx. at least 600 users use the app per day) (A
> minority of users may be hitting this crash over and over again)
> . This leads me to believe that my adapter update logic is mostly right,
> but not full proof.
>
> So I dug into the source code of ListView and BaseAdapter.
>
> The exception is thrown because ListView's mItemCount doesn't match the
> underlying adapter's item count. It happens in layoutChildren() [ListView.java
> line 
> 1432
> ]
> 
>  } 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 "
> 
>
> So in order to avoid this from happening mItemCount should be updated as
> soon as the adapter has changed its content. So I searched for locations in
> the code where mItemCount is updated. I found two locations doing that. In
> setAdapter() [ListView.java 
> 431]
> and in onMeasure() [ListView.java 
> 1033].
> Consequently, if I am updating the adapter then either setAdapter() or
> onMeasure() should be executed before the comparision in layoutChildren()
> takes place, otherwise the exception will be thrown.
>
> My question is, is it possible that my code in onProgressUpdate() that
> appends to adapter can get executed between onMeasure() and layoutChildren()
> of the ListView? AFAIU, all three of these methods (onProgressUpdate,
> onMeasure, layoutChildren) run on the same GUI thread.
>
> I call notifyDataSetChanged immediately after I add to adapter in
> onProgressUpdate(). I looked into its source code. It calls methods on
> DataSetObservable and DataSetObserver. I couldn't find how it could directly
> lead to the updating of mItemCount of the ListView, clearly I don't know
> much of the internal layout code.
>
> Please let me know what you think. I am trying to understand this mechanism
> as thoroughly as possible.
>
> Thanks in advance.
>
> Links:
> [1]
> http://www.mail-archive.com/android-developers@googlegroups.com/msg60355.html
> [2]
> http://www.mail-archive.com/android-developers@googlegroups.com/msg65814.html
> [3]
> http://groups.google.com/group/android-developers/browse_thread/thread/77722caa85f87697
> [4]
> http://groups.google.com/group/android-developers/browse_thread/thread/a451221261cb6a93/2ab5bea015c38437?lnk=gst&q=For+Google+about+BaseAdapter+class#2ab5bea015c38437
> [5] ListView.java source code I refered to:
> http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/widget/ListView.java;h=7c8151e65132a91aecadd2048fe205bd1c6768a9;hb=HEAD
>
> --
> Jayesh
>
>  --
> You received this message because you are subscribed to the Google
> Groups "Android Developers" group.
> To post to this group, send email to android-developers@googlegroups.com
> To unsubscri

[android-developers] IllegalStateException after ListView's adapter has changed

2010-02-21 Thread Jayesh Salvi
Hi,

This is regarding the exception:  "java.lang.IllegalStateException: The
content of the adapter has changed but ListView did not receive a
notification." - seen on Android 1.6+

This problem has been discussed in the past [1][2][3][4], and I have
followed all the solutions suggested in those threads. However, few of my
users still hit this crash. So I did some source code lookup and have some
questions.

Here is the description of what my app is doing:

I use a ListView and populate it with an adapter. The adapter is a direct
derivative of BaseAdapter. I populate the list progressively. As the items
are downloaded from network they get added to the adapter. The fetching of
items is done in doInBackground() and when they are ready to get added to
the adapter I invoke publishProgress(), in the onProgressUpdate() method I
add new items one-by-one to the adapter. As soon as I add the item to the
adapter, I invoke notifyDataSetChanged().

I believe this is as per the best practices that Android developers have
suggested in above mentioned threads.

Despite this I get crash reports with this exception. They are rare, but not
as rare as ignorable. I myself have hit this crash on my phone/emulator only
1-2 times in last couple of months. The user reported crashes are roughly 1
to 3 per day (approx. at least 600 users use the app per day) (A minority of
users may be hitting this crash over and over again)
. This leads me to believe that my adapter update logic is mostly right, but
not full proof.

So I dug into the source code of ListView and BaseAdapter.

The exception is thrown because ListView's mItemCount doesn't match the
underlying adapter's item count. It happens in layoutChildren() [ListView.java
line 
1432
]

 } 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 "


So in order to avoid this from happening mItemCount should be updated as
soon as the adapter has changed its content. So I searched for locations in
the code where mItemCount is updated. I found two locations doing that. In
setAdapter() [ListView.java
431]
and in onMeasure() [ListView.java
1033].
Consequently, if I am updating the adapter then either setAdapter() or
onMeasure() should be executed before the comparision in layoutChildren()
takes place, otherwise the exception will be thrown.

My question is, is it possible that my code in onProgressUpdate() that
appends to adapter can get executed between onMeasure() and layoutChildren()
of the ListView? AFAIU, all three of these methods (onProgressUpdate,
onMeasure, layoutChildren) run on the same GUI thread.

I call notifyDataSetChanged immediately after I add to adapter in
onProgressUpdate(). I looked into its source code. It calls methods on
DataSetObservable and DataSetObserver. I couldn't find how it could directly
lead to the updating of mItemCount of the ListView, clearly I don't know
much of the internal layout code.

Please let me know what you think. I am trying to understand this mechanism
as thoroughly as possible.

Thanks in advance.

Links:
[1]
http://www.mail-archive.com/android-developers@googlegroups.com/msg60355.html
[2]
http://www.mail-archive.com/android-developers@googlegroups.com/msg65814.html
[3]
http://groups.google.com/group/android-developers/browse_thread/thread/77722caa85f87697
[4]
http://groups.google.com/group/android-developers/browse_thread/thread/a451221261cb6a93/2ab5bea015c38437?lnk=gst&q=For+Google+about+BaseAdapter+class#2ab5bea015c38437
[5] ListView.java source code I refered to:
http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/widget/ListView.java;h=7c8151e65132a91aecadd2048fe205bd1c6768a9;hb=HEAD

--
Jayesh

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en