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

AndroidAndroid Cursor

Android Problem Overview


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?

Android Solutions


Solution 1 - Android

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

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

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

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.

Solution 5 - Android

How about using foreach loop:

Cursor cursor;
for (Cursor c : CursorUtils.iterate(cursor)) {
    //c.doSth()
}

However my version of CursorUtils should be less ugly, but it automatically closes the cursor:

public class CursorUtils {
public static Iterable<Cursor> iterate(Cursor cursor) {
    return new IterableWithObject<Cursor>(cursor) {
        @Override
        public Iterator<Cursor> iterator() {
            return new IteratorWithObject<Cursor>(t) {
                @Override
                public boolean hasNext() {
                    t.moveToNext();
                    if (t.isAfterLast()) {
                        t.close();
                        return false;
                    }
                    return true;
                }
                @Override
                public Cursor next() {
                    return t;
                }
                @Override
                public void remove() {
                    throw new UnsupportedOperationException("CursorUtils : remove : ");
                }
                @Override
                protected void onCreate() {
                    t.moveToPosition(-1);
                }
            };
        }
    };
}

private static abstract class IteratorWithObject<T> implements Iterator<T> {
    protected T t;
    public IteratorWithObject(T t) {
        this.t = t;
        this.onCreate();
    }
    protected abstract void onCreate();
}

private static abstract class IterableWithObject<T> implements Iterable<T> {
    protected T t;
    public IterableWithObject(T t) {
        this.t = t;
    }
}
}

Solution 6 - Android

import java.util.Iterator;
import android.database.Cursor;

public class IterableCursor implements Iterable<Cursor>, Iterator<Cursor> {
	Cursor cursor;
	int toVisit;
	public IterableCursor(Cursor cursor) {
		this.cursor = cursor;
		toVisit = cursor.getCount();
	}
	public Iterator<Cursor> iterator() {
		cursor.moveToPosition(-1);
		return this;
	}
	public boolean hasNext() {
		return toVisit>0;
	}
	public Cursor next() {
	//	if (!hasNext()) {
	//		throw new NoSuchElementException();
	//	}
		cursor.moveToNext();
		toVisit--;
		return cursor;
	}
	public void remove() {
		throw new UnsupportedOperationException();
	}
}

Example code:

static void listAllPhones(Context context) {
	Cursor phones = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
	for (Cursor phone : new IterableCursor(phones)) {
		String name = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
		String phoneNumber = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
		Log.d("name=" + name + " phoneNumber=" + phoneNumber);
	}
	phones.close();
}

Solution 7 - Android

The Do/While solution is more elegant, but if you do use just the While solution posted above, without the moveToPosition(-1) you will miss the first element (at least on the Contact query).

I suggest:

if (cursor.getCount() > 0) {
	cursor.moveToPosition(-1);
	while (cursor.moveToNext()) {
          <do stuff>
    }
}

Solution 8 - Android

The cursor is the Interface that represents a 2-dimensional table of any database.

When you try to retrieve some data using SELECT statement, then the database will 1st create a CURSOR object and return its reference to you.

The pointer of this returned reference is pointing to the 0th location which is otherwise called as before the first location of the Cursor, so when you want to retrieve data from the cursor, you have to 1st move to the 1st record so we have to use moveToFirst

When you invoke moveToFirst() method on the Cursor, it takes the cursor pointer to the 1st location. Now you can access the data present in the 1st record

The best way to look :

Cursor cursor

for (cursor.moveToFirst(); 
     !cursor.isAfterLast();  
     cursor.moveToNext()) {
                  .........
     }

Solution 9 - Android

if (cursor.getCount() == 0)
  return;

cursor.moveToFirst();

while (!cursor.isAfterLast())
{
  // do something
  cursor.moveToNext();
}

cursor.close();

Solution 10 - Android

Initially cursor is not on the first row show using moveToNext() you can iterate the cursor when record is not exist then it return false,unless it return true,

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGraham BorlandView Question on Stackoverflow
Solution 1 - AndroidGraham BorlandView Answer on Stackoverflow
Solution 2 - AndroidAlex StylView Answer on Stackoverflow
Solution 3 - AndroidJörg EisfeldView Answer on Stackoverflow
Solution 4 - AndroidPankajView Answer on Stackoverflow
Solution 5 - Androidaleksander.w1992View Answer on Stackoverflow
Solution 6 - Android18446744073709551615View Answer on Stackoverflow
Solution 7 - AndroidLarsView Answer on Stackoverflow
Solution 8 - AndroidRaj ShahView Answer on Stackoverflow
Solution 9 - AndroidChanghoonView Answer on Stackoverflow
Solution 10 - Androidkundan kamalView Answer on Stackoverflow