2013年1月22日火曜日

Cursor.moveToFirst は別に必須ではない

Android の SQLiteDatabase なんかを使用してデータベースに問い合わせを行い、その結果を Cursor で受け取る、という処理は毎日の習慣のような感じでいつも使うわけですが、何故かこれに対して、次のような Cursor.moveToFirst してから Cursor.moveToNext するコードがよく見られます。

Cursor cursor = db.query(...);
if (cursor.moveToFirst()) {
    do {
        cursor.getString(...);
        ...
    } while (cursor.moveToNext());
}

多分最初のカーソル位置がどこにあるか良く分からないとか、名前的にまあ First に移動してから Next に移動するのが正しいんだろう、という感覚で書いてると思うんですが、実際は Cursor.getPosition のドキュメントに次のような記載があります。

When the row set is first returned the cursor will be at positon -1, which is before the first row. 
行セットが最初に返されたとき、カーソルの位置は -1, つまり最初の行の一つ前に設定されています。
つまり、 Cursor インスタンスを受け取ってから最初の Cursor.moveToNext 呼び出しで先頭行を取り出せることはちゃんと仕様上保証されているので、次のように単純なループで書いて大丈夫です。

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

何となくコピペプログラミングで感染しまくってる感があったので、ただそれだけですがメモ。

2 件のコメント:

  1. 複数のデータを取得した場合Cursor.moveToFirstから始めてmoveToNext で次に移動するという手順を踏まないと最初の一つが欠落するという現象があるのでネット上のサンプルでCursor.moveToFirstが使われているのはそれの対策だと思います。
    例外などのエラーは起きないので動作上は必須ではないですが先頭のデータが回収できません。

    仕様書が間違っているか、バグのどちらかだと思いますが、プログラムのコードの読み方的に仕様書が間違っているようにおもえます。

    返信削除
  2. と思ったけどすいません、違いました。 こちらの手違いでちゃんとmoveToNextで最初から出来ますね。

    返信削除