Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android SQLite SQLiteOpenHelper IllegalStateException - DB Already Closed Error

This has been driving me crazy for a few days now. I have an android application that is pretty complex. It uses multiple threads to pull data from a server and populate the SQLite database. I'm using a singleton to reference my extension of SQLiteOpenHelper. I'm opening and closing the database in each of my activities.

The error ONLY occurs in a situation when I'm 4 activities deep and then try to back out. I've tried various ways of opening and closing the database, including moving the close from the onDestroy() to the onPause() methods and also adding another open to the onResume().

Also of note, my activities make heavy use of ListViews and ExpandableListViews, which I understand could cause the database to close based on this article: http://darutk-oboegaki.blogspot.com/2011/03/sqlitedatabase-is-closed-automatically.html

I've gone through the code and made sure i'm either closing all my cursors, or, if they are being assigned to an adapter, calling startManagingCursor().

Does anybody have a clue as to what's going on?

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

UPDATE: I've fixed the problem, but not sure WHY this fixed it. So, maybe someone out there knows or could explain.

When I'm in the 4th activity of the stack of activities, I was attempting to close the db via db.close(). No matter WHERE I put this, in the onCreate after I get the data i need, or in the onStop or onDestroy, it will produce this error. If I DO NOT close the db, I'm not having the problem. So, something is causing the db to automatically close. The strange thing is, although I'm using an expandableListView in this final activity, I'm NOT using a cursorAdapter. Anyone have any thoughts? Would love to understand this.

like image 690
SBerg413 Avatar asked Jun 30 '11 13:06

SBerg413


3 Answers

Since this question has gotten a good deal of attention, I wanted to answer it and describe what I've learned and what worked for me to correct this problem in my large, database-driven application:

  1. Do NOT use managed cursors. There's a reason why they're deprecated. They're completely problematic. Realistically, there's very few scenarios where you actually need to use a managed cursor anyway. Instead, run your query and populate an object with the results. If you're querying for multiple row, create an ArrayList<> of your object to hold all the rows. What I do now is create a function that runs the query and passes me back my ArrayList<> rather than a cursor in the return. I close the cursor within the function and I'm done. For a ListViews, you'll no longer be able to use a SimpleCursorAdapter. Just convert all of these to a BaseAdapter and use your ArrayList<> object to populate it.

  2. DO NOT FORGET TO CLOSE ALL YOUR CURSORS. This can also wreak havoc on your app's db connections. I thought I was doing this but, sure enough, found a spot that I wasn't explicitly closing a cursor. So, go through your app and double check all of them.

I'm also using a singleton DatabaseHelper object. I declare a static DatabaseHelper object within my SQLiteOpenHelper class so that I'm getting the same instance every time.

I now have a stable running app that no longer gets these DB errors. I hope this information is helpful to some of you.

like image 146
SBerg413 Avatar answered Oct 20 '22 17:10

SBerg413


use CursorAdapter.changeCursor(null) ,Can slow the emergence of this bug,But can not completely solve the problom ,Unknown period of time will appear again. This has been driving me crazy too!

like image 37
Julien Avatar answered Oct 20 '22 18:10

Julien


I had also the same problem 'db already closed exception with a cursor invalid statement in fillWindow() and IllegalStatementException'. What I did was I put my cursor (w/c also comes from SimpleCursorAdapter) to an instance variable instead of a method variable then on my onStop and onPause methods I call stopManagingCursor then on my onResume and onStart methods I call startManagingCursor.

It solved my problem for me and I didn't find any error or warning messages in my logcat after that :) Hope this helps anyone also.

like image 1
gilsaints88 Avatar answered Oct 20 '22 18:10

gilsaints88