0

为什么可以在模拟器Cursor.getLong()Cursor.getString()正常工作,但在运行相同版本 Android 的实际设备上却不能?

我对 Android记事本教程的第三版进行了一些补充,其中涉及以编程方式更改笔记的标题。(我最近在获取当前 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 都是连续的,但事实并非如此。以下是我获取正确数据并防止任何未来强制关闭光标的两个建议:

  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)); 
    

    要遍历新游标,您只需检查 moveToNext() 的返回值。当光标的索引设置为-1(就像它是新的一样)时,moveToNext() 将移动到索引0true仅在有有效数据时返回,否则如果没有行 moveToNext() 则返回false

  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 回答