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
The Activity Must Be Exported or Contain an Intent-Filter
Using Asynctask with Passing a Value
Center Message in Android Dialog Box
Deadobjectexception on Android App
Rotate Marker and Move Animation on Map Like Uber Android
Android Studio - Failed to Find Target Android-18
What Is the Use of Basecolumns in Android
How to Install Various Python Libraries in Jython
How to Set -Source 1.7 in Android Studio and Gradle
Why Does a Try/Catch Block Create New Variable Scope
How to Get String Response from Retrofit2
Driver Jdbc Postgresql with Android
Android Gives Error "Cannot Fit Requested Classes in a Single Dex File"
How to Remove a Specific Element from a JSONarray
How to Implement the Android Actionbar Back Button