База данных Android - Не удается выполнить эту операцию, поскольку пул соединений был закрыт

У меня странная проблема с базой данных и курсорами Android. Время от времени (очень редко) бывает, что я получил сообщение о сбоях от клиентов. Трудно узнать, почему он падает, так как у меня ~ 150 000 активных пользователей и, возможно, 1 отчет в неделю или около того, так что это действительно небольшая ошибка. Вот исключение:

STACK_TRACE=java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:144)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at sk.mildev84.agendareminder.a.c.a(SourceFile:169)

Перед каждым курсором "итерация и исследование" я использую этот код, чтобы убедиться, что все в порядке:

db = instance.getWritableDatabase();
cursor = db.rawQuery(selectQuery, null);

if (isCursorEmptyOrNotPrepared(cursor)) {
    ...
    }

private synchronized boolean isCursorEmptyOrNotPrepared(Cursor cursor) {
        if (cursor == null)
            return true;

        if (cursor.isClosed())
            return true;

        if (cursor.getCount() == 0) // HERE IT CRASHES
            return true;

        return false;
    }

И он падает на линию:

if (cursor.getCount() == 0)

Кто-нибудь знает почему? Я думаю, я проверяю все возможные исключения и условия... Почему здесь работает мое приложение?

PS: все методы базы данных синхронизированы, и я правильно открываю и закрываю базы данных/курсоры во всех случаях, я проверял их много раз.

Ответ 1

Проблема
Если вы попробуете другую операцию после закрытия базы данных, она предоставит вам это исключение. Если db.close(); освобождает ссылку на объект, закрывая объект, если последняя ссылка была выпущена.

Решение
Храните один экземпляр SQLiteOpenHelper (Singleton) в статическом контексте. Сделайте ленивую инициализацию и synchronize этот метод. Например,

public class DatabaseHelper
{
    private static DatabaseHelper instance;

    public static synchronized DatabaseHelper getInstance(Context context)
    {
        if (instance == null)
            instance = new DatabaseHelper(context);

        return instance;
    }
//Other stuff... 
}

И вам не нужно закрывать его? Когда приложение отключится, он отпустит ссылку на файл, если он даже держится за него.
т.е. вы не должны закрывать БД, так как он будет использоваться снова при следующем вызове. Так что просто удалите

db.close();

Подробнее см. в Одно соединение с SQLite

Ответ 2

Вы просто удалите Удалить db.close()

Ответ 3

У меня тоже была эта проблема. мой класс SQLiteOpenHelper был Singleton, а также закрывал db после каждой операции CRUD. После того, как мои методы (CRUD) синхронизированы в моем классе SQLiteOpenHelper, я больше не получил ошибок:)

Ответ 4

Такая же проблема возникла у меня, поэтому после прочтения explain я удалил      db.close();
от
     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
и
public int delete(Uri uri, String selection, String[] selectionArgs)

ContentProvider
Не нужно db.close(), поскольку ContentProvider сам позаботится о закрытии базы данных.