Diese Woche habe ich alles über ContentProvider gelernt und die SQLiteOpenHelper-Klasse verwendet, um die Erstellung und Aktualisierung der Datenbank innerhalb eines Anbieters zu verwalten. Insbesondere habe ich das NotePad-Beispiel aus dem Beispielverzeichnis des SDK gelesen.
Jetzt kann ich sehen, dass SQLiteOpenHelper eine close () -Methode hat. Ich bin mir bewusst, dass das Öffnen offener Datenbanken eine schlechte Praxis ist und Speicherlecks und so weiter verursachen kann (es sei denn, diese Diskussion geht in die richtige Richtung). Wenn ich die Klasse in einer Aktivität verwenden würde, würde ich einfach close () in der onDestroy () -Methode aufrufen, aber meines Wissens hat ContentProvider nicht den gleichen Lebenszyklus wie Aktivitäten. Der Code für NotePad scheint nie close () aufzurufen, daher würde ich gerne annehmen, dass er von SQLiteOpenHelper oder einem anderen Teil des Puzzles verarbeitet wird, aber ich würde es wirklich gerne sicher wissen. Ich vertraue dem Beispielcode auch nicht so sehr ...
Zusammenfassung der Fragen: Wann sollten wir die Datenbank bei einem Anbieter schließen, wenn überhaupt?
quelle
Antworten:
Laut Dianne Hackborn (Android Framework Engineer) muss die Datenbank bei einem Inhaltsanbieter nicht geschlossen werden.
Vielen Dank an @bigstones für diesen Hinweis.
quelle
shutdown()
wenn Sie Reboelectric ContentProvider-Unit-Tests durchführen möchten.Diese Frage ist etwas alt, aber immer noch sehr relevant. Beachten Sie, dass Sie db.close () in Ihrer ContentProvider-Implementierung NICHT aufrufen müssen , wenn Sie die Dinge auf "moderne" Weise ausführen (z. B. LoaderManager verwenden und CursorLoaders erstellen, um einen ContentProvider in einem Hintergrundthread abzufragen) . Beim Versuch, auf den ContentProvider in einem Hintergrundthread zuzugreifen, kam es zu allen möglichen Abstürzen im Zusammenhang mit CursorLoader / AsyncTaskLoader, die durch Entfernen der Aufrufe von db.close () behoben wurden.
Wenn Sie also auf Abstürze stoßen, die so aussehen (Jelly Bean 4.1.1):
Oder dies (ICS 4.0.4):
Caused by: java.lang.IllegalStateException: database /data/data/com.hindsightlabs.paprika/databases/Paprika.db (conn# 0) already closed at android.database.sqlite.SQLiteDatabase.verifyDbIsOpen(SQLiteDatabase.java:2215) at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:436) at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:422) at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:79) at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164) at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:156) at android.content.ContentResolver.query(ContentResolver.java:318) at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:49) at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:35) at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240) at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51) at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40) at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) ... 4 more
Oder wenn in LogCat Fehlermeldungen angezeigt werden, die folgendermaßen aussehen:
Überprüfen Sie anschließend Ihre ContentProvider-Implementierung und stellen Sie sicher, dass Sie die Datenbank nicht vorzeitig schließen. Nach dieser wird erhalten die Contentprovider automatisch gereinigt , wenn der Prozess ohnehin getötet wird, so dass Sie die Datenbank vor der Zeit nicht brauchen , zu schließen.
Stellen Sie jedoch sicher, dass Sie immer noch richtig sind:
quelle
Ich folge Mannaz ' Antwort und habe gesehen, dass der
SQLiteCursor(database, driver, table, query);
Konstruktor veraltet ist. Dann habe ich diegetDatabase()
Methode gefunden und anstelle desmDatabase
Zeigers verwendet. und Konstruktor für Rückwärtsfähigkeit gehaltenquelle
Wenn Sie möchten, dass Ihre Datenbank automatisch geschlossen wird, können Sie
CursorFactory
beim Öffnen Folgendes angeben:Hier sind die Klassen:
quelle
Schließen Sie es, wenn Sie damit fertig sind, vorzugsweise in einem Endblock, damit Sie sicherstellen können, dass es passiert. Ich weiß, das klingt ein wenig banal und unkompliziert, aber es ist wirklich die einzige Antwort, die ich kenne. Wenn Sie die Datenbank öffnen und eine Aktion ausführen, schließen Sie sie, wenn Sie mit dieser Aktion fertig sind, es sei denn, Sie wissen, dass sie erneut benötigt wird (in diesem Fall müssen Sie sie unbedingt schließen, sobald sie nicht mehr benötigt wird).
quelle
Wenn Sie Ihren Inhaltsanbieter innerhalb einer Aktivität verwenden, glaube ich nicht, dass Sie die Verbindung des Inhaltsanbieters aufrechterhalten müssen. Sie können das mit startManagingCursor zurückgegebene Cursorobjekt einfach verwalten. In der Aktivitätsmethode onPause können Sie den Inhaltsanbieter freigeben. (Sie können es in onResume neu laden). Unter der Annahme, dass der Aktivitätslebenszyklus normalerweise begrenzt ist, würde dies ausreichen. (Zumindest nach mir;))
quelle