Android: Cannot Perform This Operation Because the Connection Pool Has Been Closed

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.

java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed

My problem is solved. The reason is rather simple, it's just in one place that I used the SQLiteDatabase.close() so it crashed.
Even so, it's still a good opportunity for me to learn more about Android database connection pool. Here is something that useful for me to solve this problem.

We call SQLiteOpenHelper.getWrteableDatabase() and SQLiteOpenHelper.getReadableDatabase() to get the SQLiteDatabase object. The logic is rather simple, if the SQLiteDatabase object is already for business, it will return it, else it will create a new one and prepare for business and then return it. So, that means, if the SQLiteOpenHelper is singleton, the SQLiteDatabase object is singleton too. If we call the SQLiteOpenHelper.close() or SQLiteDatabase.close(), they will all call SQLiteDatabase.close(). In SQLiteDatabase.close(), it will judge current references number, if all the references released, the SQLiteConnectionPool will be closed.

So, that means, if all the Store (used to store and query data from db) objects use the same SQLiteDatabaseHelper, they will use the same SQLiteDatabase too. If I closed SQLiteDatabase in one Store object, it will affect another Store object. Even I added the sychronized keyword in one Store methods, it will only lock methods in the same object. That is the real reason caused this exception.

Then I removed the SQLiteDatabase.close() logic, it worked fine.

But, what if I want to close the SQLiteDatabase. I found out one way for my case. The OpenHelperManager is used to calculate current connections number and if the number is zero, then it can close the db connection.

public class OpenHelperManager {
@SuppressLint("StaticFieldLeak")
private static boolean isClosed = false;
private static int instanceCount = 0;

public static synchronized void releaseHelper(PalmDB helper) {
instanceCount--;
LogUtils.e(String.format("releasing helper %s, instance count = %s", helper, instanceCount));
if (instanceCount <= 0) {
if (helper != null) {
LogUtils.e(String.format("zero instances, closing helper %s", helper));
helper.close();
isClosed = true;
}
if (instanceCount < 0) {
LogUtils.e(String.format("too many calls to release helper, instance count = %s", instanceCount));
}
}
}

public static synchronized void requireConnection() {
isClosed = false;
instanceCount++;
}

public static boolean isClosed() {
return isClosed;
}
}

Here, the PalmDB extends SQLiteOpenHelper:

public class PalmDB extends SQLiteOpenHelper {
// ...
}

In the store object:

protected SQLiteDatabase getWritableDatabase() {
OpenHelperManager.requireConnection();
return mPalmDatabase.getWritableDatabase();
}

protected void closeDatabase(SQLiteDatabase database) {
OpenHelperManager.releaseHelper(mPalmDatabase);
}

I use getWritableDatabase() method to get SQLiteDatabase, and at the same time increase the count of instance in OpenHelperManager. Add use closeDatabase() method instead of SQLiteDatabase.close() to close database. In closeDatabase() method, I called OpenHelperManager.releaseHelper(mPalmDatabase), which will decrease the count of instance in OpenHelperManager. If the count of instance is zero, then close the SQLiteOpenHelper, that will close SQLiteDatabse object. It worked fine for my case. You may also use some atomic classes like AtomicInteger to calculate the count.

That is the answer for my problem, hope it helps for you.

How to fix: java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed?

Multiple things might cause this issue:
a. You are calling db.close() before accessing the data.
b. Or db.close() is being called by some other method and you are still trying to access data from database from other method with same database reference.

Android error: Cannot perform this operation because the connection pool has been closed

SQLiteConnectionPooling was added in after Android 4.1. Whereas in previous versions a cursor object would simply try to reopen a database if a query or other operation was made on a connection that was closed, with Connection Pooling, an exception is thrown. The NotesDBAdapter is probably a throwback which may have broken compatibility with 4.2.2.



Related Topics



Leave a reply



Submit