我经常看到的代码涉及迭代一个数据库查询的结果,做一些与每一行,然后移动到下一行。 典型的例子如下。
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
的方法。 当然必须有一个更合适的方法?
Answer 1:
最简单的方法是这样的:
while (cursor.moveToNext()) {
...
}
光标第一个结果行之前开始,所以在第一次循环如果存在这种移动到第一个结果。 如果光标是空的,或最后一行已经被处理,则循环整齐地退出。
当然,不要忘记关闭游标一旦你用它做,最好是在finally
条款。
Cursor cursor = db.rawQuery(...);
try {
while (cursor.moveToNext()) {
...
}
} finally {
cursor.close();
}
如果你的目标API 19+,你可以使用try-与资源。
try (Cursor cursor = db.rawQuery(...)) {
while (cursor.moveToNext()) {
...
}
}
Answer 2:
我发现经过一个光标最好看的方法如下:
Cursor cursor;
... //fill the cursor here
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
// do what you need with the cursor here
}
不要忘记之后关闭游标
编辑:给定的解决方案是伟大的,如果你需要遍历一个光标,你是不负责的。 一个很好的例子是,如果你是在一个方法采取光标作为参数,并且您需要扫描光标给定值,而不必担心光标的当前位置。
Answer 3:
我只是想指出的第三替代也可以工作,如果光标不在起始位置:
if (cursor.moveToFirst()) {
do {
// do what you need with the cursor here
} while (cursor.moveToNext());
}
Answer 4:
如何使用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;
}
}
}
Answer 5:
下面可能是更好的方法:
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
//your code to implement
cursor.moveToNext();
}
}
cursor.close();
上面的代码将确保它会经历整个迭代,将无法逃脱第一和最后一次迭代。
Answer 6:
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();
}
Answer 7:
在DO /虽然解决方案更优雅,但如果你只使用上面贴了当的解决方案,而不moveToPosition(-1),你将错过第一个元素(至少在联系查询)。
我建议:
if (cursor.getCount() > 0) {
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
<do stuff>
}
}
Answer 8:
if (cursor.getCount() == 0)
return;
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
// do something
cursor.moveToNext();
}
cursor.close();
Answer 9:
最初光标不在使用中的第一行显示moveToNext()
你可以遍历光标时记录不存在,那么return false
,除非它return true
,
while (cursor.moveToNext()) {
...
}
文章来源: What's the best way to iterate an Android Cursor?