Правильно ли работает документация Android Cursor.moveToNext ()? - PullRequest
6 голосов
/ 13 мая 2011

логическое android.database.Cursor.moveToNext () документация говорит:

http://developer.android.com/reference/android/database/Cursor.html#moveToNext%28%29

Переместить курсор на следующую строку.

Этот метод вернет false, если курсор уже находится за последней записью в наборе результатов.


Однако моя книга говорит, что для извлечения данных из курсора необходимо сделать следующее:

Cursor myCursor = myDatabase.query(...);
if (myCursor.moveToFirst()) {
    do {
    int value = myCursor.getInt(VALUE_COL);
    // use value
    } while (myCursor.moveToNext());
}

Кто прав? Это не может быть правдой. Если вы не видите противоречия, представьте, что myCursor вернул 1 строку из запроса. Первый вызов getInt () будет работать, но затем moveToNext () вернет true, потому что он не «уже» после последней записи в наборе результатов. Так что теперь курсор будет находиться за последней записью, а второй вызов getInt () сделает что-то неопределенное.

Я подозреваю, что документация неверна, и вместо этого следует читать:

Этот метод вернет false, если курсор «уже на» последней записи в наборе результатов.

Должен ли курсор быть уже перед (не AT) последней записью, прежде чем метод moveToNext () вернет false?

Нет, Snark, пожалуйста

Ответы [ 5 ]

21 голосов
/ 08 ноября 2011

Более простая идиома:

Cursor cursor = db.query(...);
while (cursor.moveToNext()) {
    // use cursor
}

Это работает, потому что начальная позиция курсора равна -1, см. Cursor.getPosition () документы.

Выможно также найти использование курсоров в самом исходном коде Android с помощью этого запроса поиска кода Google .Семантика курсора одинакова в базе данных SQLite и поставщиках контента.

Ссылки: этот вопрос .

6 голосов
/ 13 мая 2011

Дословно от API:

Возвращает: было ли перемещение успешным.


Итак, это означает, что:

Курсор в первой строке -> moveToNext () -> курсор во второй строке -> второй строки нет -> вернуть false


Если вам нужны подробности, перейдите к источнику: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.3_r1/android/database/AbstractCursor.java#AbstractCursor.moveToNext%28%29

public final boolean moveToNext() {
  return moveToPosition(mPos + 1);
}

public final boolean moveToPosition(int position) {
    // Make sure position isn't past the end of the cursor
    final int count = getCount();
    if (position >= count) {
        mPos = count;
        return false;
    }
2 голосов
/ 07 ноября 2012

Похоже, что это связано с реализацией Android AbstractCursor и в Jellybean не работает.

Я реализовал следующий модульный тест, чтобы продемонстрировать мне проблему с помощью MatrixCursor:

@Test
public void testCursor() {
  MatrixCursor cursor = new MatrixCursor(new String[] { "id" });
  for (String s : new String[] { "1", "2", "3" }) {
    cursor.addRow(new String[] { s });
  }

  cursor.moveToPosition(0);
  assertThat(cursor.moveToPrevious(), is(true));

  cursor.moveToPosition(cursor.getCount()-1);
  assertThat(cursor.moveToNext(), is(true));

  assertThat(cursor.moveToPosition(c.getCount()), is(true));
  assertThat(cursor.moveToPosition(-1), is(true));
}

Все утверждения не выполняются, в отличие от документации для moveToNext, moveToPrevious и moveToPosition.

При чтении кода в API 16 для AbstractCursor.moveToPosition (int position) это выглядит как намеренное поведение, то есть методы явно возвращают false в этих случаях, в отличие от документации.

Какпримечание: поскольку код Android, установленный на существующих устройствах, не может быть изменен, я принял подход написания своего кода, чтобы он соответствовал поведению существующей реализации Android, а не документации.то есть.При реализации моих собственных Cursors / CursorWrappers я переопределяю методы и пишу свой собственный javadoc, описывающий отход от существующей документации.Таким образом, мои Cursors / CursorWrappers остаются взаимозаменяемыми с существующими курсорами Android без нарушения поведения во время выполнения.

2 голосов
/ 25 июня 2012

Я думаю, что стараюсь держаться подальше от решений, основанных на скрытом предположении, таком как: я надеюсь, что sqlite никогда не изменит его api и что курсор всегда будет начинаться с первого элемента.

Кроме того, мне почти всегда удавалось заменить оператор while на оператор for. Итак, мое решение показывает, с чего я ожидал начать курсор, и избегает использования оператора while:

for( boolean haveRow = c.moveToFirst(); haveRow; haveRow = c.moveToNext() ) {
...
}

почему показывает, что курсор должен начинаться с первой строки, а через 6 месяцев вы, возможно, отлаживаете свой собственный код, и будете удивляться, почему вы не сделали этого явным, чтобы вы могли легко его отладить.

0 голосов
/ 13 ноября 2017

Cursor.moveToNext (), возвращающий логическое значение, полезен, только если он не будет перемещать курсор за последней записью в наборе данных.Таким образом, я отправил отчет об ошибке в трекере проблем документации.

https://issuetracker.google.com/issues/69259484

Он рекомендует следующее предложение:
"Этот метод вернет false, если текущий (в то времявыполнения) запись является последней записью в наборе, и следующей записи не будет. "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...