Cursor的getLong()和getString()在仿真器上工作,但不在等效设备上工作

时间:2012-08-12 19:41:24

标签: android android-emulator

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

我对Android Notepad tutorial的第三版进行了一些补充,涉及以编程方式更改笔记的标题。 (我最近在Obtaining the current Android view and forcing it to be redrawn询问了这个项目。)我的更改在我的模拟器中工作正常,但在我的测试手机上导致应用程序结束“很遗憾,程序停止了”。

以下是发生这种情况的方法:

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

2 个答案:

答案 0 :(得分:1)

  

Cursor的getLong()和getString()在模拟器上工作但不是等效设备...我知道获取光标至少部分有效,因为note.getColumnName(1)在调试器中工作正常。我还确认getLong()和getString()的参数正确显示。

Cursor的getLong()和getString()方法在仿真器和实际设备上的工作方式相同。

如果您查看LogCat,您会发现问题的原因是没有数据:

  

android.database.CursorIndexOutOfBoundsException:请求索引0,大小为0

看来Cursor为空,你的表(在设备上)是否有任何行?


从评论中添加

正如我们发现你假设你的所有行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)); 
    

    要遍历新的Cursor,只需检查moveToNext()的返回值。当Cursor的索引设置为-1时(就像它是新的一样),moveToNext()将移动到索引0并仅在有有效数据时返回true,否则如果不是rows 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);
        }
    }
    

答案 1 :(得分: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);
}