Этот вопрос немного стар, но по-прежнему весьма уместен. Обратите внимание, что если вы делаете что-то «современным» способом (например, используя LoaderManager и создавая CursorLoaders для запроса ContentProvider в фоновом потоке), убедитесь, что вы НЕ вызываете db.close() в своей реализации ContentProvider. Я получал всевозможные сбои, связанные с CursorLoader/AsyncTaskLoader, когда он пытался получить доступ к ContentProvider в фоновом потоке, которые были устранены путем удаления вызовов db.close().
Так что, если вы работаете в аварии, которые выглядят, как это (Jelly Bean 4.1.1):
Caused by: 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:677)
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:143)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at android.content.ContentResolver.query(ContentResolver.java:388)
at android.content.ContentResolver.query(ContentResolver.java:313)
at com.hindsightlabs.paprika.loaders.GroceryListLoader.loadInBackground(GroceryListLoader.java:147)
at com.hindsightlabs.paprika.loaders.GroceryListLoader.loadInBackground(GroceryListLoader.java:1)
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
Или это (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
Или, если вы видите сообщения об ошибках в LogCat, которые выглядят так:
Cursor: invalid statement in fillWindow()
Затем проверьте выполнение ContentProvider и убедитесь, что вы не закрывая базу данных преждевременно. В соответствии с ContentProvider будет автоматически очищаться, когда процесс будет убит в любом случае, поэтому вам не нужно закрывать его базу данных раньше времени.
Тем не менее, убедитесь, что вы все еще правильно:
- Закрывая курсоры, которые возвращаются из ContentProvider.query(). (CursorLoader/LoaderManager делает это автоматически для вас, но если вы выполняете прямые запросы вне рамки LoaderManager или вы внедрили собственный подкласс CursorLoader/AsyncTaskLoader, вам нужно убедиться, что вы очищаете свои курсоры правильно.)
- Реализация вашего ContentProvider в потокобезопасном режиме. (Самый простой способ сделать это, чтобы убедиться, что ваши методы доступа к базе данных, завернутые в блоке с синхронизируется.)
Dianne Hackborn сказал, что [нет необходимости закрывать db] (http://groups.google.com/d/msg/android-developers/NwDRpHUXt0U/jIam4Q8-cqQJ). – bigstones
Это самая важная информация в этой теме. Я дал ему ответ. – philipp