web-dev-qa-db-fra.com

Base de données Android - Impossible d'effectuer cette opération car le pool de connexions a été fermé

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.

13
qkx

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

27
Giru Bhai

Vous venez de supprimer Supprimer db.close ()

0
Gary Wong

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!
}
0
Verdigrass

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 :)

0
Sherry

Le même problème m'est arrivé, donc après avoir lu explication j'ai enlevé
db.close();
de
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
et
public 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.

0
Lokesh Tiwari