What's the best way to iterate an Android Cursor?

I frequently see code which involves iterating over the result of a database query, doing something with each row, and then moving on to the next row. Typical examples are as follows.

Cursor cursor = db.rawQuery(...);
cursor.moveToFirst();
while (cursor.isAfterLast() == false) 
{
    ...
    cursor.moveToNext();
}
Cursor cursor = db.rawQuery(...);
for (boolean hasItem = cursor.moveToFirst(); 
     hasItem; 
     hasItem = cursor.moveToNext()) {
    ...
}
Cursor cursor = db.rawQuery(...);
if (cursor.moveToFirst()) {
    do {
        ...                 
    } while (cursor.moveToNext());
}

These all seem excessively long-winded to me, each with multiple calls to Cursor methods. Surely there must be a neater way?


Solution 1:

The simplest way is this:

while (cursor.moveToNext()) {
    ...
}

The cursor starts before the first result row, so on the first iteration this moves to the first result if it exists. If the cursor is empty, or the last row has already been processed, then the loop exits neatly.

Of course, don't forget to close the cursor once you're done with it, preferably in a finally clause.

Cursor cursor = db.rawQuery(...);
try {
    while (cursor.moveToNext()) {
        ...
    }
} finally {
    cursor.close();
}

If you target API 19+, you can use try-with-resources.

try (Cursor cursor = db.rawQuery(...)) {
    while (cursor.moveToNext()) {
        ...
    }
}

Solution 2:

The best looking way I've found to go through a cursor is the following:

Cursor cursor;
... //fill the cursor here

for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
    // do what you need with the cursor here
}

Don't forget to close the cursor afterwards

EDIT: The given solution is great if you ever need to iterate a cursor that you are not responsible of. A good example would be, if you are taking a cursor as argument in a method, and you need to scan the cursor for a given value, without having to worry about the cursor's current position.

Solution 3:

I'd just like to point out a third alternative which also works if the cursor is not at the start position:

if (cursor.moveToFirst()) {
    do {
        // do what you need with the cursor here
    } while (cursor.moveToNext());
}

Solution 4:

Below could be the better way:

if (cursor.moveToFirst()) {
   while (!cursor.isAfterLast()) {
         //your code to implement
         cursor.moveToNext();
    }
}
cursor.close();

The above code would insure that it would go through entire iteration and won't escape first and last iteration.