Что это лучший способ, чтобы выполнить итерации курсор Андроид?
Я часто вижу код, который включает в себя итерацию по результату запроса базы данных, что-то делать с каждой строкой, а затем перейти к следующей строке. Типичными примерами являются следующие.
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());
}
все они кажутся мне чрезмерно многословными, каждый с несколькими вызовами Cursor
методы. Конечно, должен быть более аккуратный способ?
10 ответов:
самый простой способ это:
while (cursor.moveToNext()) { ... }
курсор начинается до первая строка результата, поэтому на первой итерации это переходит к первому результату если он существует. Если курсор пуст или последняя строка уже обработана, то цикл завершается аккуратно.
конечно, не забудьте закрыть курсор, как только вы закончите с ним, желательно в
finally
предложения.Cursor cursor = db.rawQuery(...); try { while (cursor.moveToNext()) { ... } } finally { cursor.close(); }
если вы нацелены на API 19+, Вы можете использовать попытки с ресурсами.
try (Cursor cursor = db.rawQuery(...)) { while (cursor.moveToNext()) { ... } }
самый красивый способ, который я нашел, чтобы пройти через курсор, заключается в следующем:
Cursor cursor; ... //fill the cursor here for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { // do what you need with the cursor here }
Не забудьте закрыть курсор после
EDIT: данное решение отлично подходит, если вам когда-нибудь понадобится повторить курсор, за который вы не несете ответственности. Хорошим примером может быть, если вы принимаете курсор в качестве аргумента в методе, и вам нужно сканировать курсор на заданное значение, не беспокоясь о текущей позиции курсора.
Я просто хотел бы указать на третий вариант, который также работает, если курсор не находится в начальной позиции:
if (cursor.moveToFirst()) { do { // do what you need with the cursor here } while (cursor.moveToNext()); }
Как насчет использования цикла foreach:
Cursor cursor; for (Cursor c : CursorUtils.iterate(cursor)) { //c.doSth() }
однако моя версия CursorUtils должна быть менее уродливой, но она автоматически закрывает курсор:
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; } } }
ниже может быть лучше так:
if (cursor.moveToFirst()) { while (!cursor.isAfterLast()) { //your code to implement cursor.moveToNext(); } } cursor.close();
приведенный выше код гарантирует, что он будет проходить через всю итерацию и не будет избегать первой и последней итерации.
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(); } }
пример кода:
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(); }
решение Do / While более элегантно, но если вы используете только решение While, опубликованное выше, без moveToPosition(-1) вы пропустите первый элемент (по крайней мере, в запросе контакта).
Я предлагаю:
if (cursor.getCount() > 0) { cursor.moveToPosition(-1); while (cursor.moveToNext()) { <do stuff> } }
if (cursor.getCount() == 0) return; cursor.moveToFirst(); while (!cursor.isAfterLast()) { // do something cursor.moveToNext(); } cursor.close();
изначально курсор не находится на первой строке шоу с помощью
moveToNext()
вы можете повторить курсор, когда запись не существует, то этоreturn false
,если неreturn true
,while (cursor.moveToNext()) { ... }
прежде чем знать, как перебирать курсор, вы должны знать, что такое курсор вообще или в Android.
Курсор в Android-это интерфейс, который представляет собой результирующий набор, возвращаемый базой данных(в терминах непрофессионалов курсор-это таблица со строками и столбцами).
интерфейс Курсора имеет довольно полезно методы, чтобы поиграть. Например, получение общего количества строк и столбцов. Вы можете запросить столбец имя, вы даже можете запросить значения, хранящиеся в определенной строке. Как только вы узнаете, что эта итерация над курсором-это просто еще одна программная вещь, которую вы бы сделали в прошлом.
Вот как вообще, как я перебираю курсор.
Получить общее количество строк с помощью функции getCount () интерфейса Курсораint rowSize = cursor.getCount(); cursor.moveToFirst(); // resets the value to -1 for(int i=0;i<rowSize;i++) { cursor.moveToNext(); // moves to next row // Write your logic } cursor.close(); // close the cursor at the end