如何调试Android API30+下的CursorIndexOutOfBoundsException错误
Android 11+版本出现CursorIndexOutOfBoundsException问题排查与解决
我是一名开发新手,正在为学校项目制作一款健康应用。该应用在Android 11(API 30)上运行正常,但在Android 11以上(API 30+)版本中出现错误。
报错代码
private fun refreshMe(){ val helper = profileHelper(applicationContext) val db = helper.readableDatabase val rs = db.rawQuery("SELECT * FROM uProfile", null) rs.moveToLast() nama.text = rs.getString(1) //THE ERROR HAPPEN HERE umur.text = rs.getString(2) jk.text = rs.getString(3) data.text = rs.getString(4) kadarAu.text = rs.getString(5) kadarGd.text = rs.getString(6) kadarHb.text = rs.getString(7) kadarCh.text = rs.getString(8) kadarTdSis.text = rs.getString(9) kadarTdDia.text = rs.getString(10) rs.close() }
错误日志
FATAL EXCEPTION: main Process: com.lhsproj.labhealthpocket, PID: 10098 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.lhsproj.labhealthpocket/com.lhsproj.labhealthpocket.MainActivity}: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 0 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:205) at android.os.Looper.loop(Looper.java:294) at android.app.ActivityThread.main(ActivityThread.java:8177) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) Caused by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 0 at android.database.AbstractCursor.checkPosition(AbstractCursor.java:521) at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:139) at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:53) at com.lhsproj.labhealthpocket.MainActivity.refreshMe(MainActivity.kt:63) at com.lhsproj.labhealthpocket.MainActivity.onCreate(MainActivity.kt:251) at android.app.Activity.performCreate(Activity.java:8595) at android.app.Activity.performCreate(Activity.java:8573) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:205) at android.os.Looper.loop(Looper.java:294) at android.app.ActivityThread.main(ActivityThread.java:8177) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
问题核心
错误提示CursorIndexOutOfBoundsException: Index -1 requested, with a size of 0说明:查询返回的游标是空的(表uProfile中没有数据),但你直接调用rs.moveToLast()后未做判断就读取数据,此时游标仍处于初始位置-1,触发崩溃。
Android 11+出现问题的大概率原因是存储权限变更,导致数据库文件未正确创建或读取,表中无数据。
修复方案
先处理空游标,避免崩溃
修改refreshMe()方法,先判断游标是否有有效数据:private fun refreshMe(){ val helper = profileHelper(applicationContext) val db = helper.readableDatabase val rs = db.rawQuery("SELECT * FROM uProfile", null) // 先判断是否能移动到最后一条数据 if (rs.moveToLast()) { nama.text = rs.getString(1) umur.text = rs.getString(2) jk.text = rs.getString(3) data.text = rs.getString(4) kadarAu.text = rs.getString(5) kadarGd.text = rs.getString(6) kadarHb.text = rs.getString(7) kadarCh.text = rs.getString(8) kadarTdSis.text = rs.getString(9) kadarTdDia.text = rs.getString(10) } else { // 无数据时的默认显示逻辑 nama.text = "请完善个人资料" umur.text = "--" jk.text = "--" // 其余控件也设置默认值 } rs.close() }排查数据库权限与创建逻辑
- 检查自定义
profileHelper(SQLiteOpenHelper子类)的数据库存储路径,Android 11+建议使用内部存储路径(如getDatabasePath()),避免使用外部存储的旧路径; - 确认
profileHelper的onCreate()方法是否正确创建了uProfile表,字段数量要匹配你读取的索引(索引1到10对应至少11个字段,索引0通常是主键); - 卸载旧版本后重新安装,避免旧数据库缓存导致的异常。
- 检查自定义
代码优化建议
- 不要直接用索引读取字段,改用
getColumnIndex(),避免表结构变更引发错误:nama.text = rs.getString(rs.getColumnIndex("nama_column_name")) - 用
try-finally确保游标和数据库资源正确释放:private fun refreshMe(){ val helper = profileHelper(applicationContext) val db = helper.readableDatabase var rs: Cursor? = null try { rs = db.rawQuery("SELECT * FROM uProfile", null) if (rs.moveToLast()) { // 赋值逻辑 } } finally { rs?.close() db.close() } }
- 不要直接用索引读取字段,改用
内容的提问来源于stack exchange,提问作者Lalu Habib Sasiwimba
相关产品推荐
相关产品推荐

