I don't know if my assumptions are right, anyway I pushed an update that
seems to fix the bug (at least, I have zero reports since I put the new
version online, whereas I used to have a few dozens). Here is what I did
currently

   1. Removed android:onClick in my XML files
   2. Manually set the listener inside my custom adapter bindView()
   3. Avoid leaks: since the listener happens to be an activity, I unset it
   either onPause() (via AbsListView.reclaimViews(List<View>) and via a custom
   AbsListView.RecycleListener

I want to remark, I don't know if my assumptions are correct and I don't
know it this solves the bug. However if both of these are true, we have a
collision between View and Activity lifecycle. Basically, if I am right,
the View is reused in another activity (since its original one is paused)
but still has the old one set as its listener. This causes the NPE because
the old activity cursor is effectively null. Again, note that I don't have
a single proof of these assumptions: I think the whole thing would be
indeed very dangerous, but is the only coherent and conceptually right
explanation. The problem here is that I've never been able to reproduce the
bug, so I must base my assumptions on the crash reports (which are stopped
after the upgrade).

I'd like some Android dev on the list to tell if this is indeed possible,
because it would be a dangerous thing (it could also be the case for memory
leaks). I read the sources myself, but didn't find the relevant code. There
is AbsListView.RecycleBin, but it's an instance field of the ListView and I
don't think that the whole list view is reused among different Activities
in this case.

Related question on StackOverflow<http://stackoverflow.com/q/10475359/315306>

2012/5/7 Jason Teagle <teagle.ja...@gmail.com>

>   Unfortunately the crash reports don't show the device model. The NPE
> happens when the user clicks a row or one of the buttons in a row (since
> all three actions share the same code).
>
> I have imagined a possible cause for this issue. Looking into the sources
> (android/view/View.java) here is what the constructor does when it founds
> android:onClick in XML: an anonymous listener is created, and this
> listener will call the method on the Context returned by View.getContext(),
> but this context may be a different instance than the one currently holding
> the view. This is because 
> Adapter.getView()<http://developer.android.com/reference/android/widget/Adapter.html#getView(int,%20android.view.View,%20android.view.ViewGroup)>gives
>  a chance for reusing an already existing View, and the default
> strategy for CursorAdapter (as seen in the sources) is to reuse that simply
> if it's not null. So here is my scenario
>
>    1. Instance#1 of MyActivity is created, its listview is set up and
>    shown. Instance#1 is set as the listener for the list_item view, as per
>    android:onClick in my XML layout
>    2. onPause is called on instance#1, which causes my method to set
>    adapter's cursor to null
>    3. the system decides that a new instance of MyActivity is needed, so
>    instance#2 is created. A new cursor is also created and its contents are
>    shown in the list view (via bindView()), but the list item views are
>    recycled somehow, since they were kept in a cache. The old views still keep
>    a reference to instance#1, so when the click event is triggered,
>    instance#1.onClick() is fired and it founds a null cursor, thus throwing
>    the NPE
>
> This explanation requires a little bit of imagination, but I think it's
> still realistic, even if all is to be demonstrated. I am writing a
> separated, minimal test case to dive into the Android classes with the
> debugger, but it's not simple. I use an activity with a list view as the
> only content view, and a list_item with an android:onClick property defined
> in XML. My goal is to see if a new instance of the activity can be created
> even when another one is already available. From the Android doc, this
> would be perfectly legitimate, but is not easy to trigger. The second step
> is to click the list item and compare the list_item's context with the
> current Activity. If they are different, we have caught it.
>
> Does anybody have any suggestion or experience on this?
>
> @Jason, as per the tap tempo, the algorithm to detect the BPM requires
> three taps at enough close intervals, and the resulting value must also be
> in the constraints. If you try to tap while you listen a song, it will do
> its job
>
> @Blake, I can argue it from the stack trace. The NPE is throws at this line
> int position = cursor.getPosition();
> so the cursor is obviously null, and the only code that change the cursor
> (and the adapter) is onPause(), where I set adapter.changeCursor(null);
>
>
>
> --
> 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
>

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

Reply via email to