光标的getLong()和getString()在模拟器上工作,但不是等效设备

问题描述:

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

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

游标的getLong()和GetString()在模拟器上工作,但不等同装置...我知道,获取光标至少部分地工作,因为note.getColumnName(1)工作正常调试器。我也证实getLong()和getString()的参数正确显示。

游标的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()将移动到索引0并返回true,除非有有效的数据,否则如果没有行moveToNext()返回false

  2. 始终假定光标可能是空的,明白一个空指针不不等于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); 
        } 
    } 
    
+0

是的,有八个保存的注释(行)。在我尝试编辑它们之前,它们都会在应用程序加载时正常显示。 – Pops 2012-08-12 19:57:27

+0

'fetchNote(int i)'的代码是什么? – Sam 2012-08-12 19:59:02

+0

我已将它添加到问题中。它与[Android开发人员教程](http://developer.android.com/training/notepad/notepad-ex3.html)中给出的代码完全相同,除了已更改的变量名称。 – Pops 2012-08-12 20:03:42

这里的差异是由巧合造成的。当我问这个问题的时候,我从来没有在模拟器中删除过笔记。其结果是,我有笔记有1,2,3和4数据库ID当我问数据库返回的它包含音符的数量,我成立了一个

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