¿Cuál es la mejor manera de iterar un Cursor Android?

Con frecuencia veo código que implica iterar sobre el resultado de una consulta de base de datos, hacer algo con cada fila y, a continuación, pasar a la siguiente fila. Ejemplos típicos son los siguientes.

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()); } 

Todos ellos me parecen excesivamente largos, cada uno con múltiples llamadas a los métodos Cursor . Seguramente debe haber una manera más limpia?

La forma más sencilla es esta:

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

El cursor comienza antes de la primera fila de resultados, por lo que en la primera iteración se mueve al primer resultado si existe . Si el cursor está vacío o la última fila ya ha sido procesada, el bucle sale correctamente.

Por supuesto, no olvide cerrar el cursor una vez que haya terminado con él, preferiblemente en una cláusula final.

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

Si apunta a la API 19+, puede utilizar try-with-resources.

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

La mejor manera de mirar que he encontrado para ir a través de un cursor es el siguiente:

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

No olvide cerrar el cursor después

EDIT: La solución dada es grande si alguna vez necesita para iterar un cursor que no son responsables. Un buen ejemplo sería, si está tomando un cursor como argumento en un método, y necesita escanear el cursor para un valor dado, sin tener que preocuparse por la posición actual del cursor.

Sólo me gustaría señalar una tercera alternativa que también funciona si el cursor no está en la posición inicial:

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

¿Cómo sobre el uso de bucle foreach:

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

Sin embargo, mi versión de CursorUtils debería ser menos fea, pero automáticamente cierra el 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; } } } 

Abajo podría ser la mejor manera:

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

El código anterior aseguraría que pasaría por iteración completa y no escapará la primera y última iteración.

La solución Do / While es más elegante, pero si utiliza sólo la solución While que se ha publicado anteriormente, sin moveToPosition (-1), se perderá el primer elemento (al menos en la consulta de contacto).

Yo sugiero:

 if (cursor.getCount() > 0) { cursor.moveToPosition(-1); while (cursor.moveToNext()) { <do stuff> } } 
 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(); } } 

Ejemplo de código:

 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(); } 
 if (cursor.getCount() == 0) return; cursor.moveToFirst(); while (!cursor.isAfterLast()) { // do something cursor.moveToNext(); } cursor.close(); 

Inicialmente el cursor no está en la primera fila usando moveToNext() puede iterar el cursor cuando el registro no existe, entonces return false , a menos que return true ,

 while (cursor.moveToNext()) { ... } 
  • Ordenar una lista en orden ascendente por fecha desde sqlite
  • Cómo mostrar las imágenes guardadas en la carpeta sdcard en android
  • Vincular los datos del cursor a un diseño no listado
  • Android ¿cómo codificar ahora si requery está obsoleto?
  • Uso del cursor en android
  • Sqlite no pudo leer row 0 col -1 de cursorwindow de cursor en servicio de alarma
  • Cree un cursor de matriz en lugar de DB
  • Obtener problemas de rendimiento de contactos
  • ¿Cuándo cerrar el cursor en Android?
  • Android obtiene un cursor sólo con contactos que tienen un correo electrónico listado> android 2.0
  • Consultar el cursor MediaStore utilizando una carpeta específica
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.