迭代 Android Cursor 的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10723770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the best way to iterate an Android Cursor?
提问by Graham Borland
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. Surely there must be a neater way?
这些对我来说似乎都过于冗长,每个都对Cursor
方法进行了多次调用。当然必须有一个更整洁的方法吗?
回答by Graham Borland
The simplest way is this:
最简单的方法是这样的:
while (cursor.moveToNext()) {
...
}
The cursor starts beforethe 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()) {
...
}
}
回答by Alex Styl
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.
编辑:如果您需要迭代您不负责的游标,则给定的解决方案非常好。一个很好的例子是,如果您将游标作为方法中的参数,并且您需要扫描游标以获取给定值,而不必担心游标的当前位置。
回答by J?rg Eisfeld
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());
}
回答by aleksander.w1992
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<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;
}
}
}
回答by Pankaj
Below could be the better way:
下面可能是更好的方法:
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
//your code to implement
cursor.moveToNext();
}
}
cursor.close();
The above code would insure that it would go through entire iteration and won't escape first and last iteration.
上面的代码将确保它会经历整个迭代并且不会逃脱第一次和最后一次迭代。
回答by 18446744073709551615
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();
}
}
Example code:
示例代码:
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();
}
回答by Lars
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()) {
<do stuff>
}
}
回答by susemi99
if (cursor.getCount() == 0)
return;
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
// do something
cursor.moveToNext();
}
cursor.close();
回答by Rajshah
The cursoris the Interface that represents a 2-dimensional
table of any database.
的光标是一个表示界面2-dimensional
的任何数据库的表。
When you try to retrieve some data using SELECT
statement, then the database will 1st create a CURSOR objectand return its reference to you.
当您尝试使用SELECT
语句检索某些数据时,数据库将首先创建一个CURSOR 对象并将其引用返回给您。
The pointer of this returned reference is pointing to the 0th locationwhich is otherwise called as before the first location of the Cursor, so when you want to retrieve data from the cursor, you have to 1st move to the 1st record so we have to use moveToFirst
此返回引用的指针指向第 0 个位置,该位置在 Cursor 的第一个位置之前被称为其他位置,因此当您想从游标中检索数据时,您必须首先移动到第 1 条记录,因此我们必须使用移至第一
When you invoke moveToFirst()
method on the Cursor,it takes the cursor pointer to the 1st location. Now you can access the data present in the 1st record
当您moveToFirst()
在Cursor上调用方法时,它将光标指针指向第一个位置。现在您可以访问第一条记录中的数据
The best way to look :
最佳观看方式:
Cursor cursor
光标光标
for (cursor.moveToFirst();
!cursor.isAfterLast();
cursor.moveToNext()) {
.........
}
回答by kundan kamal
Initially cursor is not on the first row show using moveToNext()
you can iterate the cursor when record is not exist then it return false
,unless it return true
,
最初游标不在第一行显示使用moveToNext()
您可以在记录不存在时迭代游标然后它return false
,除非它return true
,
while (cursor.moveToNext()) {
...
}