安卓SQLite SQLiteOpenHelper报IllegalStateException - 数据库已关闭错误

12
这几天一直让我很困扰。我有一个相当复杂的Android应用程序。它使用多个线程从服务器拉取数据并填充SQLite数据库。我使用单例来引用我的SQLiteOpenHelper的扩展。我在每个活动中打开和关闭数据库。
错误仅在我深入4个活动并尝试退出时发生。我尝试了各种方法来打开和关闭数据库,包括将close()从onDestroy()移动到onPause()方法,并在onResume()中添加另一个open()。
此外,我的活动大量使用ListViews和ExpandableListViews,根据这篇文章,我理解这可能会导致数据库关闭: http://darutk-oboegaki.blogspot.com/2011/03/sqlitedatabase-is-closed-automatically.html 我已经检查了代码,确保我要么关闭了所有游标,要么如果它们被分配给适配器,则调用startManagingCursor()。
有人知道发生了什么吗?
java.lang.RuntimeException: Unable to resume activity {com.fieldone/com.fieldone.DispatchActivity}: java.lang.IllegalStateException: database /data/data/com.fieldone/databases/InterstateAirConditioning-1602814322.db already closed
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3347)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3362)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2162)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:144)
    at android.app.ActivityThread.main(ActivityThread.java:4937)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: database /data/data/com.fieldone/databases/InterstateAirConditioning-1602814322.db already closed
    at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:237)
    at android.database.sqlite.SQLiteQuery.requery(SQLiteQuery.java:145)
    at android.database.sqlite.SQLiteCursor.requery(SQLiteCursor.java:567)
    at android.app.Activity.performRestart(Activity.java:3836)
    at android.app.Activity.performResume(Activity.java:3857)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3337)
    ... 10 more

更新:我已经解决了问题,但不确定为什么会这样。也许有人知道或能够解释一下。

当我在活动堆栈的第四个活动中时,我试图通过db.close()关闭数据库。无论我把它放在哪里,在获取所需数据后的onCreate中,还是在onStop或onDestroy中,都会产生此错误。如果我不关闭数据库,我就不会遇到这个问题。因此,某些东西会导致数据库自动关闭。奇怪的是,虽然我在最终活动中使用了可扩展列表视图,但我没有使用游标适配器。有人有什么想法吗?希望能理解这个问题。

3个回答

20

由于这个问题受到了很多关注,我想回答它并描述一下我学到的东西以及在我的大型数据库驱动应用程序中修复此问题所使用的方法:

  1. 不要使用托管游标。它们被弃用有其原因,存在很大问题。实际上,在很少情况下,您真正需要使用托管游标。相反,运行查询并使用结果填充对象。如果您正在查询多行,请创建一个ArrayList<>来保存所有行的对象。现在我会创建一个函数来运行查询,并将我的ArrayList<>传递回来,而不是在返回中使用游标。我在函数内部关闭游标,然后完成。对于ListViews,您将无法再使用SimpleCursorAdapter。只需将所有这些转换为BaseAdapter,并使用您的ArrayList<>对象进行填充即可。

  2. 不要忘记关闭所有游标。这也可能会破坏您的应用程序的数据库连接。我以为我已经做到了,但是我找到了一个没有明确关闭游标的地方。因此,请检查您的应用程序并仔细检查所有游标。

我还使用单例DatabaseHelper对象。我在SQLiteOpenHelper类中声明了一个静态DatabaseHelper对象,以便每次都获得相同的实例。

现在,我有一个稳定运行的应用程序,不再出现这些数据库错误。我希望这些信息对您有所帮助。


2

使用CursorAdapter.changeCursor(null)可以延缓出现此bug的时间,但无法完全解决问题,未知时间后可能会再次出现。这个问题也令我感到很头痛!


1

我也遇到了同样的问题:“在fillWindow()中,db已关闭异常和无效语句的游标IllegalStatementException”。我的解决方法是将我的游标(也来自SimpleCursorAdapter)放到实例变量中,而不是方法变量中,然后在onStop和onPause方法中调用stopManagingCursor,在onResume和onStart方法中调用startManagingCursor。

这个方法对我很有帮助,之后我没有发现任何错误或警告信息:) 希望这也能帮助其他人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接