43 votes

Exception: tentative d'acquérir une référence sur une fermeture SQLiteClosable

J'ai posté ce retour en Mai sur le [android-les développeurs] Google Groupe. Je n'ai jamais entendu parler et n'a pas été en mesure de reproduire le problème jusqu'à ce qu'un de mes élèves a fait la semaine dernière. J'ai pensé à la poster ici et de voir si il a sonné les cloches pour n'importe qui.

Dans l'un de mes exemples de code, j'ai la méthode suivante:

static Cursor getAll(SQLiteDatabase db, String orderBy) {
        return(db.rawQuery("SELECT * FROM restaurants "+orderBy, null));

}

Quand je le lance, de façon sporadique, j'obtiens ceci:

05-01 14:45:05.849: ERROR/AndroidRuntime(1145):
java.lang.IllegalStateException: attempt to acquire a reference on a
close SQLiteClosable
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:31)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:56)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:49)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1118)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1092)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
apt.tutorial.Restaurant.getAll(Restaurant.java:14)

Cela n'a aucun sens pour moi. La base de données est certainement ouverte. L' SQLiteClosable est le SQLiteQuery créé par SQLiteQueryDriver, et je voyons aucune preuve qu'il y est un objet de la piscine ou quelque chose se passe ici qui pourrait expliquer comment un "nouveau" SQLiteClosable est déjà fermé. L' fait qu'elle est sporadique (ce qui signifie la même INTERFACE utilisateur opérations parfois déclenchement de l'exception, mais pas toujours) suggère une sorte de piscine, course l'état, ou quelque chose...mais je ne sais pas où.

Pensées?

Merci!

Mise à JOUR: Le code en question est de la LunchList tutoriaux de mon Android Programmation Tutoriels livre. C'est un peu dispersé et pas très adapté pour les publier directement dans la. Vous pouvez télécharger le code de ce livre à partir du lien ci-dessus si vous voulez prendre un coup d'oeil. Je ne me souviens pas exactement de l'édition du tutoriel de l'étudiant était en train de travailler, bien qu'il soit dans le Tutoriel 12-Tutoriel 16 gamme. J'étais plupart du temps en espérant de trouver quelqu'un qui avait trébuché sur ce problème avant et avait une probable. Je suis assez certain que ma base de données est ouverte. Merci encore!

53voto

Jarett Points 1730

Cette un me rendait fou pour le plus de temps. La solution que j'ai trouvé est assez simple: ne pas garder les références à SQLiteDatabase objets. Au lieu de cela, utilisez un SQLiteOpenHelper et appelez - getWritableDatabase() chaque fois que vous en avez besoin. À partir de la documentation:

public synchronisé SQLiteDatabase getWritableDatabase()

Créer et/ou ouvrir une base de données qui sera utilisé pour la lecture et l'écriture. Une fois ouvert avec succès, la base de données est mise en cache, de sorte que vous pouvez appeler cette méthode à chaque fois, vous devez écrire à la base de données.

La réponse était là tout le temps.

9voto

darutk Points 351

SQLiteDatabase est fermé automatiquement sous certaines conditions.

http://darutk-oboegaki.blogspot.com/2011/03/sqlitedatabase-is-closed-automatically.html

getCount() et onMove() les méthodes de Curseur déclencher une requête à l'aide de SQLiteQuery. Après toutes les données requises sont obtenues, SQLiteQuery décrémente le compteur de référence de la SQLiteDatabase instance. Lorsque la référence du compte à rebours atteint 0, la base de données est fermée.

Notez que la requête peut être exécutée de manière asynchrone et dans un tel cas, getCount() renvoie -1 si elle est appelée avant SQLiteQuery finitions de préparation des données.

1voto

cikabole Points 11

J'ai eu le même problème pendant quelques jours, et ma solution a été de mettre la méthode open () juste avant ma requête et la méthode close () après l'opération de base de données. Cela ressemble à quelque chose comme ça.

 open();
Cursor cur=db.query(DATABASE_TABLE_CON, null, null, null, null, null, " name ASC");
close();
return cur;
 

Cela fonctionne très bien, mais je suis préoccupé par le coût des ressources. Je ne suis pas sûr de dépenser plus de ressources avec toute cette base de données d'ouverture et de fermeture avant toute action.

1voto

Dan Dyer Points 30082

J'ai été confronté à un problème similaire, malgré déjà à la suite de Jarett conseils. Dans mon cas, le problème se passe assez régulièrement sur les changements d'orientation. J'ai découvert que, pour une raison que je n'ai pas encore arrivés au bout de, mon code génère deux identiques, à peu près simultanée AsyncTasks sur un changement d'orientation (par opposition à un seul, lorsque l'activité démarre normalement). Ces tâches exécuter la même requête de base de données en même temps de différents threads.

Cette exception (ou de temps en temps certains autres SQLiteException) est le résultat. Il semble donc que ce message peut être un symptôme de problèmes de concurrence d'accès, même si elle n'est pas nécessairement la racine du problème original posté ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X