0

エミュレータでは正しく動作するのに、同じバージョンの Android を実行している実際のデバイスでは動作しないのはCursor.getLong()なぜですか?Cursor.getString()

Android のNotepad チュートリアルのバージョン 3 に、メモのタイトルをプログラムで変更する機能をいくつか追加しました。(最近、このプロジェクトについて、現在の Android ビューの取得と再描画の強制で質問しました。) 私の変更はエミュレーターでは正常に機能しますが、テスト用の電話で「残念ながら、プログラムが停止しました」という末尾が表示されます。

これが起こっている方法は次のとおりです。

public void expandNoteTitle(int i) {
    Cursor note = fetchNote(i);
    long rowId =
      note.getLong(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_ROWID));
    String title =
      note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)) + "W";
    String body =
      note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY));
    updateNote(rowId, title, body);
}

note.getColumnName(1)デバッガーで正常に動作するため、カーソルのフェッチが少なくとも部分的に機能していることはわかっています。getLong()また、との引数がgetString()正しく表示されることも確認しました。

LogCat の出力は次のとおりです。

08-12 15:35:29.735: D/AndroidRuntime(17937): Shutting down VM
08-12 15:35:29.735: W/dalvikvm(17937): threadid=1: thread exiting with uncaught exception (group=0x40a3d1f8)
08-12 15:35:29.751: E/AndroidRuntime(17937): FATAL EXCEPTION: main
08-12 15:35:29.751: E/AndroidRuntime(17937): android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
08-12 15:35:29.751: E/AndroidRuntime(17937):    at android.database.AbstractCursor.checkPosition(AbstractCursor.java:400)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:74)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at notepad.NotesDbAdapter.expandNoteTitle(NotesDbAdapter.java:212)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at notepad.NotesDbAdapter.expandNoteTitles(NotesDbAdapter.java:201)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at notepad.NotepadMain.expandTitles(NotepadMain.java:167)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at notepad.NotepadMain.onMenuItemSelected(NotepadMain.java:115)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:950)
08-12 15:35:29.751: E/AndroidRuntime(17937):    at [SNIPPED FOR LENGTH]
08-12 15:35:29.751: E/AndroidRuntime(17937):    at dalvik.system.NativeStart.main(Native Method)
08-12 15:36:49.993: I/Process(17937): Sending signal. PID: 17937 SIG: 9

のコードは次のとおりですfetchNote()。変数名を除いて、チュートリアルで指定されたバージョンと同じです。

public Cursor fetchNote(long rowId) throws SQLException {
    Cursor mCursor = database.query(true, DATABASE_TABLE, new String[] {
      KEY_ROWID, KEY_TITLE, KEY_BODY }, KEY_ROWID + "=" + rowId, null,
      null, null, null, null);
    if(mCursor != null) {
        mCursor.moveToFirst();
    }
    return mCursor;
}
4

2 に答える 2

1

カーソルの getLong() と getString() はエミュレーターでは機能しますが、同等のデバイスでは機能しません... デバッガーで note.getColumnName(1) が正常に機能するため、カーソルのフェッチが少なくとも部分的に機能することがわかっています。また、getLong() と getString() の引数が正しく表示されることも確認しました。

Cursor の getLong() メソッドと getString() メソッドは、エミュレータと実際のデバイスの両方で同じように機能します。

LogCat を見ると、問題の原因はデータがないことがわかります。

android.database.CursorIndexOutOfBoundsException: サイズ 0 のインデックス 0 が要求されました

カーソルが空であるように見えます。(デバイス上の) テーブルに行がありますか?


コメントから追加

私たちが発見したように、あなたはすべての行 ID が連続していると仮定していましたが、そうではありません。適切なデータをフェッチし、カーソルからの将来の強制終了を防ぐための 2 つの提案を次に示します。

  1. 既存のすべての行 ID を取得し、それらを反復処理します。

    Cursor notes = database.query(DATABASE_TABLE, new String[] { KEY_ROWID }, null, null, null, null, null, null);
    
    while(notes.moveToNext()) 
        expandNoteTitle(notes.getLong(0)); 
    

    新しい Cursor を反復するには、moveToNext() からの戻り値を確認するだけです。カーソルのインデックスが に設定されて-1いる場合 (新規の場合など)、moveToNext() はインデックスに移動し、有効なデータがある場合にのみ戻ります。そうでない場合、行がない場合は moveToNext() が戻り0ます。truefalse

  2. Cursor が空である可能性があることを常に想定し、空のカーソルは等しくないnullことを理解してください。

    public Cursor fetchNote(long rowId) throws SQLException {
        return database.query(true, DATABASE_TABLE, 
                new String[] { KEY_ROWID, KEY_TITLE, KEY_BODY }, 
                KEY_ROWID + "=" + rowId, null, null, null, null, null);
    }
    
    public void expandNoteTitle(long rowId) {
        Cursor note = fetchNote(rowId);
        if(note.getCount() > 0) {
            // You could also use if(cursor.moveToNext()) or if(cursor.moveToFirst()), both of these return true / false depending on whether there is valid data
    
            String title =
              note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)) + "W";
            String body =
              note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY));
            updateNote(rowId, title, body);
        }
    }
    
于 2012-08-12T19:56:18.133 に答える
0

ここでの不一致は偶然によるものです。この質問をした時点で、エミュレーターでメモを削除したことはありません。その結果、そこにあったメモのデータベース ID は 1、2、3、および 4 でした。データベースに含まれるメモの数を返すようにデータベースに要求したとき、

for(int i = 1; i <= numberOfNotes; i++) { ... }

ループ。メモの作成時に ID が次に大きい整数で割り当てられるため、これは既存の ID とのみ一致しました。デバイスでいくつかのメモを削除したため、ID は適切な 1 対 n のシーケンスではありませんでした。コードは次のようになります。

public void expandNoteTitles() {
    Cursor notes = database.query(DATABASE_TABLE, new String[] { KEY_ROWID },
      null, null, null, null, null, null);
    notes.moveToFirst();

    for(int i = 0; i < notes.getCount(); i++) {
        expandNoteTitle(notes.getLong(0));
        notes.moveToNext();
    }
}

public void expandNoteTitle(long rowId) {
    Cursor note = fetchNote(rowId);
    String title =
      note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)) + "W";
    String body =
      note.getString(note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY));
    updateNote(rowId, title, body);
}
于 2012-08-13T06:26:24.290 に答える