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:すべてのデータベースメソッドが同期され、すべてのケースでデータベース/カーソルを正しく開いたり閉じたりしています。何度も確認しました。
問題
データベースを閉じた後に別の操作を試みると、その例外が発生します。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接続
問題は明らかです
接続プールが閉じられているため、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!
}
Remove db.close()を削除するだけです
私もこの問題を抱えていました。私のSQLiteOpenHelperクラスはシングルトンであり、各CRUD操作の後にdbを閉じていました。 SQLiteOpenHelperクラスでメソッド(CRUD)を同期させた後、これ以上エラーは発生しません:)
同じ問題が発生したので、読んだ後 説明 削除しました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()は不要です。