本文翻译自: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. 这些对我来说似乎过于冗长,每个都有多次调用Cursor
方法。 Surely there must be a neater way? 当然必须有一个更简洁的方式?
参考:https://stackoom.com/question/IZK2/迭代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. 当然,完成后不要忘记关闭光标,最好是在finally
子句中。
Cursor cursor = db.rawQuery(...);
try {
while (cursor.moveToNext()) {
...
}
} finally {
cursor.close();
}
If you target API 19+, you can use try-with-resources. 如果您的目标是API 19+,则可以使用try-with-resources。
try (Cursor cursor = db.rawQuery(...)) {
while (cursor.moveToNext()) {
...
}
}
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. 一个很好的例子是,如果您将光标作为方法中的参数,并且您需要扫描光标以获得给定值,而不必担心光标的当前位置。
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());
}
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). Do / While解决方案更优雅,但是如果您只使用上面发布的While解决方案,没有moveToPosition(-1),您将错过第一个元素(至少在Contact查询中)。
I suggest: 我建议:
if (cursor.getCount() > 0) {
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
}
}
How about using foreach loop: 如何使用foreach循环:
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: 但是我的CursorUtils版本应该不那么难看,但它会自动关闭游标:
public class CursorUtils {
public static Iterable iterate(Cursor cursor) {
return new IterableWithObject(cursor) {
@Override
public Iterator iterator() {
return new IteratorWithObject(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 implements Iterator {
protected T t;
public IteratorWithObject(T t) {
this.t = t;
this.onCreate();
}
protected abstract void onCreate();
}
private static abstract class IterableWithObject implements Iterable {
protected T t;
public IterableWithObject(T t) {
this.t = t;
}
}
}