J'ai un problème étrange avec la base de données Android et les curseurs. Il arrive de temps en temps (très rarement) que des clients me signalent un crash. Il est difficile de savoir pourquoi cela se bloque, car j'ai environ 150 000 utilisateurs actifs et peut-être un rapport par semaine environ, ce qui en fait un bug mineur. Voici une exception:
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)
Avant chaque curseur "itérant et explorant", j'utilise ce code pour m'assurer que tout va bien:
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;
}
Et ça tombe à la ligne:
if (cursor.getCount() == 0)
Quelqu'un sait pourquoi? Je pense que je vérifie toutes les exceptions et conditions possibles ... Pourquoi mon application se bloque-t-elle ici?
PS: Toutes les méthodes de la base de données sont synchronisées et j'ouvre et ferme correctement la base de données/les curseurs dans tous les cas. Je l'ai vérifié plusieurs fois.
Problème
Si vous essayez une autre opération après avoir fermé la base de données, vous obtiendrez cette exception.Parce que db.close();
libère une référence à l'objet, il ferme l'objet si la dernière référence a été publiée.
Solution
Conservez une seule instance SQLiteOpenHelper
(Singleton
) dans un contexte statique. Effectuez une initialisation lente et synchronize
cette méthode. Tel que
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...
}
Et vous n'êtes pas obligé de le fermer? Lorsque l’application s’arrête, elle lâche la référence du fichier, si elle s’y maintient .
c'est à dire. Vous ne devez pas fermer la base de données car elle sera utilisée à nouveau lors du prochain appel. So Just remove
db.close();
Pour plus d'informations, voir Connexion SQLite unique
Vous venez de supprimer Supprimer db.close ()
Le problème est clair que
SQLiteCursor ne peut pas exécuter l'opération 'getCount' car le pool de connexions a été fermé
Pour éviter IllegalStateException, nous pouvons garder la base de données ouverte tout le temps si cela est approprié. Dans d'autres situations, nous devons vérifier le statut avant d'essayer getCount.
Mon expérience est la suivante:
Code défectueux:
SOLiteOpenHelper helper = new SOLiteOpenHelper(context);
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query(...);
if (cursor != null) {
cursor.getCount(); // HERE IT CRASHES
}
Perfect Code:
SOLiteOpenHelper helper = new SOLiteOpenHelper(context);
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query(...);
if (cursor != null && db.isOpen()) {
cursor.getCount(); // OK!
}
J'ai eu ce problème également. ma classe SQLiteOpenHelper était Singleton et fermait la base de données après chaque opération CRUD. Après avoir synchronisé mes méthodes (CRUD) dans ma classe SQLiteOpenHelper, je n’ai plus eu d’erreur :)
Le même problème m'est arrivé, donc après avoir lu explication j'ai enlevédb.close();
depublic int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
etpublic int delete(Uri uri, String selection, String[] selectionArgs)
méthode de ContentProvider
Pas besoin de db.close () car ContentProvider s’occupe lui-même de la fermeture de la base de données.