Często widzę kod, który polega na iteracji wyniku zapytania do bazy danych, zrobieniu czegoś z każdym wierszem, a następnie przejściu do następnego wiersza. Typowe przykłady są następujące.
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());
}
Wszystko to wydaje mi się zbyt długie, każde z wieloma wezwaniami do Cursor
metod. Z pewnością musi być lepszy sposób?
Odpowiedzi:
Najprostszy sposób to:
Kursor zaczyna się przed pierwszym wierszem wyników, więc przy pierwszej iteracji przechodzi on do pierwszego wyniku, jeśli istnieje . Jeśli kursor jest pusty lub ostatni wiersz został już przetworzony, pętla kończy się poprawnie.
Oczywiście nie zapomnij zamknąć kursora, gdy skończysz, najlepiej w
finally
klauzuli.Jeśli celujesz w API 19+, możesz użyć try-with-resources.
źródło
CursorLoader
, upewnij się, że dzwoniszcursor.moveToPosition(-1)
przed iteracją, ponieważ moduł ładujący ponownie używa kursora, gdy zmienia się orientacja ekranu. Spędziłem godzinę na śledzeniu tego problemu!Najlepiej wyglądający sposób przejścia kursora to:
Nie zapomnij później zamknąć kursora
EDYCJA: Podane rozwiązanie jest świetne, jeśli potrzebujesz powtórzyć kursor, za który nie jesteś odpowiedzialny. Dobrym przykładem jest, jeśli bierzesz kursor jako argument w metodzie i musisz przeskanować kursor pod kątem określonej wartości, nie martwiąc się o bieżącą pozycję kursora.
źródło
Chciałbym tylko wskazać trzecią alternatywę, która działa również wtedy, gdy kursor nie znajduje się w pozycji początkowej:
źródło
moveToPosition(-1)
. Obie odpowiedzi są jednakowo spójne, ponieważ oba mają dwa wywołania kursora. Myślę, że ta odpowiedź jest na wyciągnięcie ręki od odpowiedzi Borlanda, ponieważ nie wymaga-1
magicznej liczby.Co powiesz na użycie pętli foreach:
Jednak moja wersja CursorUtils powinna być mniej brzydka, ale automatycznie zamyka kursor:
źródło
Cursor
wystąpienia w każdej iteracji pętli.Poniżej może być lepszy sposób:
Powyższy kod zapewniłby, że przejdzie całą iterację i nie uniknie pierwszej i ostatniej iteracji.
źródło
Przykładowy kod:
źródło
iterator()
powinien również ponownie przeliczyć,toVisit = cursor.getCount();
którego używam,class IterableCursor<T extends Cursor> implements Iterable<T>, Iterator<T> {...
który otrzymuje klasę, wextends CursorWrapper implements MyInterface
której MyInterface definiuje metody pobierające właściwości bazy danych. W ten sposób mam Iterator oparty na kursorze <MyInterface>Rozwiązanie Do / While jest bardziej eleganckie, ale jeśli użyjesz tylko rozwiązania While opublikowanego powyżej, bez moveToPosition (-1) przegapisz pierwszy element (przynajmniej w zapytaniu Kontakt).
Sugeruję:
źródło
źródło
The Kursor jest interfejs, który oznacza
2-dimensional
tabelę dowolnej bazy danych.Podczas próby pobrania niektórych danych za pomocą
SELECT
instrukcji baza danych najpierw utworzy obiekt CURSOR i zwróci ci swoje odwołanie.Wskaźnik tego zwróconego odwołania wskazuje na 0 lokalizację która jest inaczej nazywana tak jak przed pierwszą lokalizacją Kursora, więc jeśli chcesz odzyskać dane z kursora, musisz 1. przejść do 1. rekordu, więc musimy użyć moveToFirst
Po wywołaniu
moveToFirst()
metody w Kursorze, kursor przesuwa się do 1. lokalizacji. Teraz możesz uzyskać dostęp do danych obecnych w 1. rekordzieNajlepszy sposób na wygląd:
Kursor kursora
źródło
Początkowo kursor nie jest pokazywany w pierwszym wierszu za pomocą
moveToNext()
, możesz iterować kursor, gdy rekord nie istniejereturn false
, chyba żereturn true
,źródło