私はこの質問についてstackoverflowを読んでいたのですが、まだ解決策が見つかりませんでした。時々、私のアプリがこのエラーを投げることに気づきました:
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)
...
DatabaseHelper.Javaというファイルを使用して、このアプローチを使用してインスタンスを取得します。
public static DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
次に、このようなメソッドを使用します(このエラーでcursor.moveToFirst()行でクラッシュしました)。クラッシュすることはほとんどありませんが、時にはクラッシュすることもあります。
public Profile getProfile(long id) {
SQLiteDatabase db = this.getReadableDatabase();
String selectQuery = "SELECT * FROM " + TABLE_PROFILES + " WHERE " + KEY_PROFILES_ID + " = " + id;
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
Profile profile = new Profile();
if (cursor.moveToFirst()) {
doWhatEver();
}
cursor.close();
db.close();
return profile;
}
以上で、私が使用するすべての方法で:
SQLiteDatabase db = this.getReadableDatabase(); (or Writable)
そして、カーソルとデータベースを閉じます。この場合、エラーが次の行にスローされます。
cursor.moveToFirst();
前にthis.getReadableDatabase()を呼び出している場合、エラーが原因でデータベースが閉じられていると表示される理由はわかりません。サポートしてください!ありがとうございました :)
削除する
db.close();
データベースを閉じた後に別の操作を試みると、その例外が発生します。
ドキュメント の意味:
オブジェクトへの参照を解放し、オブジェクトを閉じます...
また、 Android Sq Liteは例外を閉じました Androidデータベース接続を閉じる必要はないというフレームワークエンジニアからのコメントについて)をチェックしてください。
現在同じ問題があります。 db.close()を削除することで問題は解決しますが、この問題はマルチスレッドが原因であると思います。これが私の研究です。
SQLiteOpenHelperは、SQLiteDatabaseへの参照を保持します。getReadableDatabase()またはgetWritableDatabase()が呼び出されると、SQLiteDatabaseがclosedまたはnull、新しいSQLiteDatabaseオブジェクトが作成されます。 getメソッド内では、コードは同期ブロックで保護されていることに注意してください。
SQLiteDatabaseはSQLiteClosableのサブクラスです。 SQLiteClosableは、参照カウントスキームを実装します。
最初に作成されたとき、カウントは1です。
データベース操作メソッドが実行されると(挿入、クエリなど)、カウントが増加し、メソッドが終了するとカウントが減少します。ただし、カーソル操作は参照カウントによって保護されません。
カウントが0に減少すると、接続プールが閉じられ、メンバーSQLiteConnectionPoolオブジェクトがnullに設定され、SQLiteDatabaseはclosedになります。
SQLiteDatabase.close()は、カウントを1減らします。
したがって、シングルスレッドスキームを使用している場合、SQLiteOpenHelperが再作成するだけなので、SQLiteDatabaseを閉じることは問題ありません。
マルチスレッドを実行すると、問題が発生します。スレッドAとスレッドBの両方がgetReadableDatabase()を呼び出し、SQLiteOpenHelperが保持するSQLiteDatabaseを返し、次にスレッドAが最初にその操作を完了してSQLiteDatabase.close()を呼び出し、SQLiteDatabaseオブジェクトスレッドBがclosedしたがって、後続のdb操作呼び出しまたはカーソルメソッド呼び出しは例外をスローします。
//close database after cursor is closed like:
if(cursor.getCount() != 0){
while(cursor.moveToNext()){
//do operation
}
}
cursor.close();
database.close();
私は同じ問題を抱えていますが、それを修正することができませんでした。私は可能な手がかりを見つけました:常に実行されている同期スレッドがあります:
Item ii = dbHelper.popPendingUpload();
if (ii != null)
upload(ii);
DBHelperの内部
public Item popPendingUpload() {
SQLiteDatabase db = getReadableDatabase();
Cursor res = db
.rawQuery("SELECT * FROM items WHERE state = 0 LIMIT 1",
new String[] {});
boolean hasNext = res.moveToFirst();
Item ii = null;
if (hasNext) {
ii = //load item
}
db.close();
return ii;
}
エラーは、moveToFirst()メソッドの呼び出しでも表示されます。スレッドは無限ループでアイテムをポップアウトするため、最初に正常に機能するとき、2回目にエラーが表示されます。興味深い部分は、ブレークポイントを設定してコードをステップスルーすると、エラーが表示されなくなることです。 Android 4.1。を使用して、実際のデバイスでテストしています。
答えではありませんが、役立つかもしれません。テストを続けます。
これは、Android getApplicationContext()を使用したルームデータベースのアーキテクチャ初期化の単純なエラーです。したがって、いずれかのアクティビティで閉じた場合、他のユーザーはその例外をスローします。
基本的に、例外をスローするアクティビティだけをチェックするのではなく、db.close()のすべてのアクティビティをチェックします
私はあなたのようなエラーがあります、ここに私のコード:
try {
String sql = "SELECT * FROM "+DB_TABLEDOWNLOAD;
Cursor cursor = db.rawQuery(sql, null);
//空双引号为原表没有的字段
String temp = "";
int existIconPath = cursor.getColumnIndex("iconPath");
int existAudioID = cursor.getColumnIndex("audioID");
if (existIconPath == -1 && existAudioID == -1){
temp = "url, downed,total,path,name, audioTitle, audioFileID,\"\",\"\"";
}else if (existIconPath == -1 && existAudioID != -1){//iconPath不存在
temp = "url, downed,total,path,name, audioTitle, audioFileID,\"\",audioID";
}else if (existIconPath != -1 && existAudioID == -1){//audioID不存在
temp = "url, downed,total,path,name, audioTitle, audioFileID,iconPath,\"\"";
}else {
return;
}
db.beginTransaction();
String tempTableName = "_temp_"+DB_TABLEDOWNLOAD;
String sqlCreateTemp = " ALTER TABLE "+DB_TABLEDOWNLOAD+" RENAME TO "+tempTableName+";";
db.execSQL(sqlCreateTemp);
final String TB_TESTPAPERINFO_CREATE = "Create TABLE IF NOT EXISTS "
+ DB_TABLEDOWNLOAD
+ "(url TEXT, downed TEXT,total TEXT,path TEXT,name TEXT, audioTitle TEXT, audioFileID TEXT,iconPath TEXT, audioID TEXT);";
db.execSQL(TB_TESTPAPERINFO_CREATE);
String sqlBackupData = "INSERT INTO "+DB_TABLEDOWNLOAD+" SELECT "+temp+" FROM "+tempTableName+";";
db.execSQL(sqlBackupData);
String sqlDrop = "DROP TABLE IF EXISTS '"+tempTableName+"';";
db.execSQL(sqlDrop);
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
}finally{
db.endTransaction();
}
Db.beginTransaction()の前にreturnを使用し、beginTransactionの前に私のコードを返しますが、finallyでendTransactionを使用します。 beginTransactionおよびendTransactionを実行しない場合、例外が表示されます。
そのため、db.beginTransactionおよびendTransactionに関するコードを確認してください。
たぶん、アプリからデータベースにアクセスする前にデータベースを閉じます。
GetProfile()を編集する必要があります
public Profile getProfile(long id) {
SQLiteDatabase db = this.getReadableDatabase();
try {
String selectQuery = "SELECT * FROM " + TABLE_PROFILES + " WHERE " + KEY_PROFILES_ID + " = " + id;
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
Profile profile = new Profile();
if (cursor.moveToFirst()) {
doWhatEver();
}
cursor.close();
finally {
db.close();
}
return profile;
}