Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception: attempt to acquire a reference on a close SQLiteClosable

Tags:

android

I posted this back in May on the [android-developers] Google Group. I never heard back and was not able to reproduce the problem until one of my students did last week. I figured I'd post it here and see if it rang any bells for anyone.

In one of my code samples, I have the following method:

static Cursor getAll(SQLiteDatabase db, String orderBy) {
        return(db.rawQuery("SELECT * FROM restaurants "+orderBy, null));

}

When I run it, sporadically, I get this:

05-01 14:45:05.849: ERROR/AndroidRuntime(1145):
java.lang.IllegalStateException: attempt to acquire a reference on a
close SQLiteClosable
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:31)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:56)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:49)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1118)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1092)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
apt.tutorial.Restaurant.getAll(Restaurant.java:14)

This makes no sense to me. The database is definitely open. The SQLiteClosable is the SQLiteQuery created by SQLiteQueryDriver, and I see no evidence that there is an object pool or something going on here that might explain how a "new" SQLiteClosable is already closed. The fact that it is sporadic (meaning the same UI operations sometimes trigger the exception, but not always) suggests some sort of pool, race condition, or something...but I'm not sure where.

Thoughts?

Thanks!

UPDATE: The code in question is from the LunchList tutorials out of my Android Programming Tutorials book. It's a bit spread out and not terribly suitable for posting directly in SO. You can download the code for that book from the above link if you want to take a look at it. I do not recall exactly which edition of the tutorial the student was working on at the time, though it was in the Tutorial 12-Tutorial 16 range. I was mostly hoping to run across somebody who had tripped over this problem before and had a likely culprit. I'm fairly certain my database is open. Thanks again!

like image 849
CommonsWare Avatar asked Sep 27 '09 14:09

CommonsWare


3 Answers

This one drove me insane for the longest time. The solution I have found is fairly simple: don't keep references to SQLiteDatabase objects. Instead, use a SQLiteOpenHelper and call getWritableDatabase() every time you need one. From the docs:

public synchronized SQLiteDatabase getWritableDatabase()

Create and/or open a database that will be used for reading and writing. Once opened successfully, the database is cached, so you can call this method every time you need to write to the database.

The answer was right there the whole time.

like image 56
Jarett Millard Avatar answered Oct 24 '22 05:10

Jarett Millard


SQLiteDatabase is closed automatically under some conditions.

http://darutk-oboegaki.blogspot.com/2011/03/sqlitedatabase-is-closed-automatically.html

getCount() and onMove() methods of Cursor trigger an actual query using SQLiteQuery. After all required data are obtained, SQLiteQuery decrements the reference count of the SQLiteDatabase instance. When the reference count reaches 0, the database is closed.

Note that the query may be executed asynchronously and in such a case, getCount() may return -1 if it is called before SQLiteQuery finishes preparing data.

like image 9
darutk Avatar answered Oct 24 '22 05:10

darutk


I had same problem for a few days, and my solution was to put open() method just before my query and close() method after database operation. It looks something like this.

open();
Cursor cur=db.query(DATABASE_TABLE_CON, null, null, null, null, null, " name ASC");
close();
return cur;

It works just fine, but I'm concerned for resources cost. I'm not sure am I spending more resources with all this opening and closing database before any action.

like image 1
cikabole Avatar answered Oct 24 '22 05:10

cikabole