web-dev-qa-db-ja.com

Androidデータベース-接続プールが閉じられているため、この操作を実行できません

Android=データベースとカーソルに奇妙な問題があります。お客様からクラッシュレポートを受け取ったことがまれにあります)。150を超えているため、クラッシュの原因を特定するのは困難です。 000人のアクティブユーザーとおそらく1週間あたり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:すべてのデータベースメソッドが同期され、すべてのケースでデータベース/カーソルを正しく開いたり閉じたりしています。何度も確認しました。

14
qkx

問題
データベースを閉じた後に別の操作を試みると、その例外が発生します。db.close();はオブジェクトへの参照を解放するため、最後の参照が解放された場合はオブジェクトを閉じます。

ソリューション
単一のSQLiteOpenHelper instance(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は次の呼び出しで再び使用されるため、DBを閉じないでください。だから削除するだけ

db.close();

詳細については、次を参照してください 単一のSQLite接続

28
Giru Bhai

問題は明らかです

接続プールが閉じられているため、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!
}
1
Verdigrass

Remove db.close()を削除するだけです

0
Gary Wong

私もこの問題を抱えていました。私のSQLiteOpenHelperクラスはシングルトンであり、各CRUD操作の後にdbを閉じていました。 SQLiteOpenHelperクラスでメソッド(CRUD)を同期させた後、これ以上エラーは発生しません:)

0
Sherry

同じ問題が発生したので、読んだ後 説明 削除しました
db.close();
から
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
そして
public int delete(Uri uri, String selection, String[] selectionArgs)
ContentProviderのメソッド
ContentProvider自体がデータベースのクローズを処理するため、db.close()は不要です。

0
Lokesh Tiwari