光标的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的都是连续的,但事实并非如此。这里是我的两个建议,以获取正确的数据,并防止任何未来的力量从你的光标关闭:
-
抓取所有现有的行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
。 -
始终假定光标可能是空的,明白一个空指针不不等于
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,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);
}
是的,有八个保存的注释(行)。在我尝试编辑它们之前,它们都会在应用程序加载时正常显示。 – Pops 2012-08-12 19:57:27
'fetchNote(int i)'的代码是什么? – Sam 2012-08-12 19:59:02
我已将它添加到问题中。它与[Android开发人员教程](http://developer.android.com/training/notepad/notepad-ex3.html)中给出的代码完全相同,除了已更改的变量名称。 – Pops 2012-08-12 20:03:42