I've created this question here as I could not comment on the last answer (comments disabled for some reason). I thought opening a new thread on this will only complicate things.
I get application crashes when I go from Activity A to Activity B and then going back to Activity A. This doesn't happen all the time - only sometimes and I am having hard time finding EXACTLY where this happens. All happens on the same device (Nexus S) but I don't believe this is a device issue.
I have few questions regarding @Martin Stine's answer.
- In the documentation it says about
changeCursor(c);
: "Change the underlying cursor to a new cursor. If there is an existing cursor it will be closed". So why do I have to stopManagingCursor(currentCursor);
- isn't that redundant?
- When I use the code offered by @Martin Stine I get a null pointer exception. The reason for that is that in the first "run" of the application
((SimpleCursorAdapter)getListAdapter())
will evaluate to NULL because no cursor was yet to be created. Sure I could check if I DON'T get a null and only then try stopping to manage the cursor but finally I decided to place my `stopManagingCursor(currentCursor); in the onPause() method of this activity. I thought this way I will for sure have a cursor to stop managing and I should do it just before I leave the Activity to a different one. The issue - I am using several cursors (one to fill up a text of an EditText field and the other for a list view) in my activity I guess not all of them are related to a ListAdapter cursor -
- How do I know which one to stop managing? If I have 3 different list views?
- Should I close all of them during
onPause()
?
- How do I get a list of all my opened cursors?
So many questions... Hope anyone could help.
When I get to onPause()
I do have a cursor to stop managing but I am yet to determine if this solves the problem as this error shows up sporadically.
Many thanks!
AFTER SOME INVESTIGATION:
I found something interesting that might give the answer to the "mysterious" side of this issue:
Activity A uses two cursors: one to fill up an EditText field. The other is to populate a ListView.
When moving from Activity A to Activity B and coming back, the field + ListView in Activity A must be filled up again. It seems like the EditText field will never have an issue with that. I couldn't find a way to get the EditText field's current cursor (like in Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor();
) and reason tells me that the EditText field will not keep it. On the other hand the ListView will "remember" its cursor from last time (from before Activity A -> Activity B). In addition, and this is the strange thing, the Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor();
will have a different ID after Activity B -> Activity A and all this WITHOUT me ever calling
Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor();
stopManagingCursor(currentCursor);
I guess in some cases, when the system needs to free resources, the cursor will be killed and when Activity B -> Activity A, the system will still try to use this old dead cursor, which will result in an Exception. And in other cases the system will come up with a new cursor that is still alive and thus no Exception will occur. This might explain why this shows up only sometimes. I guess this is hard to debug due to the difference of application speed when either running OR debugging the application. When debugging, it takes more time and thus might give the system time to come up with a new cursor or vice versa.
In my understanding this makes the usage of
Cursor currentCursor = ((SimpleCursorAdapter)currentListAdapter).getCursor();
stopManagingCursor(currentCursor);
As recommended by @Martin Stine a must in SOME cases and redundant in OTHERS: if I return to the method and the system is trying to use a dead cursor, one must create a new cursor and replace it in the ListAdapter, otherwise I get angry app users with a crashed app. In another case when the system will find itself a new cursor - the lines above are redundant as they invalidate a good cursor and create a new one.
I guess in order to prevent this redundancy I would need something like this:
ListAdapter currentListAdapter = getListAdapter();
Cursor currentCursor = null;
Cursor c = null;
//prevent Exception in case the ListAdapter doesn't exist yet
if(currentListAdapter != null)
{
currentCursor = ((SimpleCursorAdapter)currentListAdapter).getCursor();
//make sure cursor is really dead to prevent redundancy
if(currentCursor != null)
{
stopManagingCursor(currentCursor);
c = db.fetchItems(selectedDate);
((SimpleCursorAdapter)getListAdapter()).changeCursor(c);
}
else
{
c = db.fetchItems(selectedDate);
}
}
else
{
c = db.fetchItems(selectedDate);
}
startManagingCursor(c);
I would love to hear what you think about this!