Stumped as to how this ArrayIndexOutOfBounds exception is being thrown
-
28-02-2021 - |
Question
I have an AsyncTask
that queries a content provider and does some additional processing in the onPostExecute()
of that task. I have a stack trace for an exception that is very hard to reproduce, but I would like to guard against the condition or fix the code. The code is below:
int i = 0;
mIds = new long[cursor.getCount()];
while (cursor.moveToNext()) {
mIds[i++] = cursor.getLong(COLUMN_ID);
}
The crash is happening on the line in the loop. The way I see it, the only way this could happen is if:
cursor.getCount()
is returning an incorrect count.cursor
is changed while this loop is executing, but I don't think that's possible becausecursor
is a local variable. Perhaps something underlying thecursor
has changed that I'm not aware of.mIds
has changed. This shouldn't be possible because we are running on the UI thread and this is the only place in which that variable is assigned a new value. By the nature ofonPostExecute
running on the UI thread, it shouldn't be possible for this code to be running somewhere else at the same time, right?
Am I missing something?
Solution
It's difficult to see what is wrong with that loop without seeing the full code but I note from the docs:
Cursor implementations are not required to be synchronized so code using a Cursor from multiple threads should perform its own synchronization when using the Cursor.
OTHER TIPS
try this:
int i = 0;
mIds = new long[cursor.getCount()];
while (cursor.moveToNext()) {
mIds[i] = cursor.getLong(COLUMN_ID);
i++;
}
Drawing from my experiences, I always do it like this. Seems to avoid most problems.
Cursor cursor = null;
try
{
cursor = getDb().rawQuery(query, params); // your call to database here...
if (cursor == null || cursor.getCount() == 0)
return false;
cursor.moveToFirst();
mIds = new long[cursor.getCount()];
int i = 0;
do
{
mIds[i] = cursor.getLong(COLUMN_ID);
i++;
} while (cursor.moveToNext())
} catch(Exception e) {
// Do error handling
return false;
}
finally
{
closeCursor(cursor);
cursor = null;
}
return true;
Here's backup for my approach:
Is Android Cursor.moveToNext() Documentation Correct?
Does finally always execute in Java?