我经常看到这样的代码:遍历数据库查询的结果,对每一行执行一些操作,然后移动到下一行。典型例子如下。

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方法调用。肯定有更整洁的方法吧?


当前回答

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

cursor.moveToFirst();

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

cursor.close();

其他回答

最简单的方法是:

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

游标在第一个结果行之前开始,因此在第一次迭代时,它移动到第一个结果(如果它存在)。如果游标为空,或者最后一行已被处理,则循环整齐地退出。

当然,不要忘记在使用完游标后关闭它,最好是在finally子句中关闭。

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

如果你的目标是API 19+,你可以使用try-with-resources。

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
}

之后不要忘记关闭光标

编辑:如果你需要迭代一个你不负责的游标,给出的解决方案是很好的。一个很好的例子是,如果你在一个方法中使用一个游标作为参数,你需要扫描游标以获得一个给定的值,而不必担心游标的当前位置。

我只想指出第三种选择,如果光标不在起始位置,它也可以工作:

if (cursor.moveToFirst()) {
    do {
        // do what you need with the cursor here
    } while (cursor.moveToNext());
}
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();
}

最初游标不在第一行显示使用moveToNext()你可以迭代游标时,记录不存在,然后它返回false,除非它返回true,

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