База данных 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: Все методы базы данных синхронизированы, и я правильно открываю и закрываю базу данных/курсоры во всех случаях, я проверял это много раз.


person qkx    schedule 30.04.2014    source источник
comment
Опубликуйте больше кода и полную трассировку стека. Вы получаете это исключение -› где-то у вас ошибка   -  person nikis    schedule 30.04.2014
comment
Нет необходимости закрывать БД. Андроид справится. Прочтите это отличное объяснение здесь... stackoverflow .com/questions/14002022/   -  person AndroidGeek    schedule 19.08.2014
comment
@Nepster Интересно, относится ли это только к поставщикам контента?   -  person zundi    schedule 02.06.2016
comment
Пожалуйста, как вам удалось решить эту ошибку? пожалуйста, дайте мне знать, если решение @GuriBhai вам подходит. У меня такая же ошибка, но закрытие базы данных не решило мою проблему.   -  person ctu    schedule 22.11.2016


Ответы (5)


Проблема
Если вы попытаетесь выполнить другую операцию после закрытия базы данных, она выдаст вам это исключение. Поскольку 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.

person Giru Bhai    schedule 13.06.2014

Проблема ясна, что

SQLiteCursor не может выполнить операцию getCount, поскольку пул соединений закрыт.

Чтобы избежать исключения IllegalStateException, мы можем держать базу данных открытой все время, если это уместно. В других ситуациях нам нужно проверить статус перед попыткой getCount.

Мой опыт таков:

Неверный код:

SOLiteOpenHelper helper = new SOLiteOpenHelper(context);
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query(...);
if (cursor != null) {
    cursor.getCount(); // HERE IT CRASHES
}

Идеальный код:

SOLiteOpenHelper helper = new SOLiteOpenHelper(context);
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query(...);
if (cursor != null && db.isOpen()) {
    cursor.getCount(); // OK!
}
person Verdigrass    schedule 24.03.2018

Вы просто удаляете Remove db.close()

person Community    schedule 10.06.2014

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

person Sherry    schedule 16.04.2015

Та же проблема возникла и у меня, поэтому после прочтения explanation я удалено
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 сам заботится о закрытии базы данных.

person Lokesh Tiwari    schedule 22.10.2015