Android: Cannot perform this operation because the connection pool has been closed
Remove
db.close();
If you try another operation after closing the database, it will give you that exception.
The documentation says:
Releases a reference to the object, closing the object...
Also, check out
Android SQLite closed exception about a comment from an Android Framework engineer which states that it is not necessary to close the database connection, however this is only when it is managed in a ContentProvider
.
I currently have the same problem. While removing the db.close()
solves the issue for me, I think the issue is caused by multi-threading. Here is my research.
SQLiteOpenHelper
holds a reference to SQLiteDatabase
, when getReadableDatabase()
or getWritableDatabase()
called, it will return the reference, if the SQLiteDatabase
is closed or null, a new SQLiteDatabase
object will be created. Note that inside the get method, codes are guarded in a synchronized block.
SQLiteDatabase
is a subclass of SQLiteClosable
. SQLiteClosable
implements a reference counting scheme.
When first created, the count is 1.
When the database operation methods run (like insert, query), it will increase the count, and decrease the count when methods end. But the cursor operations are NOT protected by reference counting.
If the count decreases to 0, connection pool will be closed and a member
SQLiteConnectionPool
object will be set to null, and now theSQLiteDatabase
is closed;SQLiteDatabase.close()
will decrease the count by 1;
So, if you have a single-threaded scheme, closing the SQLiteDatabase
will be fine because SQLiteOpenHelper
will just re-recreate it.
If you do multi-threading, then you will run into trouble. Say thread A and thread B both call getReadableDatabase()
, and SQLiteOpenHelper
returns the SQLiteDatabase it holds, and then thread A first finished its operation and call SQLiteDatabase.close()
, now the SQLiteDatabase
object thread B has is closed so any subsequent db operation calls or cursor method calls will throw the exception.
I am having the same problem, have not been able to fix it. I have found a possible clue: I have a sync thread that is running all the time:
Item ii = dbHelper.popPendingUpload();
if (ii != null)
upload(ii);
And inside DBHelper
public Item popPendingUpload() {
SQLiteDatabase db = getReadableDatabase();
Cursor res = db
.rawQuery("SELECT * FROM items WHERE state = 0 LIMIT 1",
new String[] {});
boolean hasNext = res.moveToFirst();
Item ii = null;
if (hasNext) {
ii = //load item
}
db.close();
return ii;
}
The error also shows up in the moveToFirst() method call. As the thread is poping items out in an infinite loop, the first time it works ok, the second time the error appears. The interesting part is that if I put a breakpoint and step through the code, the error does not show any more. I am testing on a real device using Android 4.1.
I know, is not an answer, but it may help. I'll keep on testing.