2012-10-30 53 views
6

我已閱讀了很多有關此錯誤消息的主題,但無法解決我的問題。Android:java.lang.IllegalStateException:數據庫xxx.db(conn#0)已關閉

我在谷歌播放應用程序,我從用戶得到一些錯誤報告。當我嘗試應用程序時,一切正常。

在應用程序中,我正在管理一個類似30個表的大型數據庫。我正在關閉我的主要活動onDestroy()中的數據庫,並且查詢完成後關閉所有遊標。

我真的不知道爲什麼時不時用戶得到這個錯誤信息。

這裏是整個錯誤日誌:

java.lang.IllegalStateException: database /data/data/mdpi.android/databases/LocalDatabase.db (conn# 0) already closed 
at android.database.sqlite.SQLiteDatabase.verifyDbIsOpen(SQLiteDatabase.java:2213) 
at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1565) 
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1525) 
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1605) 
at mdpi.android.database.LocalDatabase.getHistoryLastSuccessfullUpdate(LocalDatabase.java:661) 
at mdpi.android.Journals$7.onItemClick(Journals.java:723) 
at android.widget.AdapterView.performItemClick(AdapterView.java:292) 
at android.widget.Gallery.onSingleTapUp(Gallery.java:960) 
at android.view.GestureDetector.onTouchEvent(GestureDetector.java:1310) 
at android.widget.Gallery.onTouchEvent(Gallery.java:937) 
at android.view.View.dispatchTouchEvent(View.java:5724) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1964) 
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1725) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970) 
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970) 
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970) 
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970) 
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970) 
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739) 
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970) 
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739) 
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2071) 
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1405) 
at android.app.Activity.dispatchTouchEvent(Activity.java:2426) 
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2019) 
at android.view.View.dispatchPointerEvent(View.java:5904) 
at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3155) 
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2670) 
at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:1000) 
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2679) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:137) 
at android.app.ActivityThread.main(ActivityThread.java:4517) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760) 
at dalvik.system.NativeStart.main(Native Method) 

而另一個問題:

java.lang.RuntimeException: Unable to start activity ComponentInfo{mdpi.android/mdpi.android.UserInformations}: java.lang.IllegalStateException: database /data/data/mdpi.android/databases/LocalDatabase.db (conn# 0) already closed 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2202) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2237) 
at android.app.ActivityThread.access$600(ActivityThread.java:139) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:4974) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
at dalvik.system.NativeStart.main(Native Method) 
Caused by: java.lang.IllegalStateException: database /data/data/mdpi.android/databases/LocalDatabase.db (conn# 0) already closed 
at android.database.sqlite.SQLiteDatabase.verifyDbIsOpen(SQLiteDatabase.java:2194) 
at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1536) 
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1496) 
at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1576) 
at mdpi.android.database.LocalDatabase.getUserInformations(LocalDatabase.java:357) 
at mdpi.android.UserInformations.onCreate(UserInformations.java:122) 
at android.app.Activity.performCreate(Activity.java:4538) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1071) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2158) 
... 11 more 

編輯:一個新的錯誤。

今天,我得到了相關的數據庫訪問一個新的錯誤:

java.lang.RuntimeException: An error occured while executing doInBackground() 

at android.os.AsyncTask$3.done(AsyncTask.java:278) 
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 
at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 
at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
at java.lang.Thread.run(Thread.java:856) 
Caused by: java.lang.NullPointerException 
at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290) 
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:115) 
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1718) 
at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1591) 
at mdpi.android.database.LocalDatabase.insertCountry(LocalDatabase.java:143) 
at mdpi.android.database.CountryTable.EnterCountry(CountryTable.java:21) 
at mdpi.android.UserInformations$insertCountryAsync.doInBackground(UserInformations.java:270) 
at mdpi.android.UserInformations$insertCountryAsync.doInBackground(UserInformations.java:1) 
at android.os.AsyncTask$2.call(AsyncTask.java:264) 
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
... 4 more 
+0

只是一個雖然。 onDestroy()的描述相當模糊。所以有一種觀點認爲在某些不明顯的情況下可能不會被調用。例如,請參閱_comments_以回答此問題:http://stackoverflow.com/a/9409517/1665128。所以,如果你不能重現這個問題,那麼在另一個數據庫中關閉數據庫可能是值得的,「更有保證」的回調。看看。 –

+0

@ full.stack.ex,謝謝你的回覆。你的想法聽起來很有趣,但我應該在哪裏調用數據庫方法,完成也許呢? –

+1

這取決於你對我的設計知之甚少。扮演班納爾上尉,看起來像真正的問題是在生命週期的某個地方的一個額外的_open_。這意味着創造和破壞必須是對稱的。所以onResume/onPause或onStart/onStop會是很好的配對。所以似乎是onCreate/onDestroy,除非有一個像長期生活的服務加上對數據庫的靜態引用或類似的東西。我會分支代碼,盡我所能將這些東西對稱放置,仔細地猴子(和人類)測試,發佈和監控,準備發佈回滾更新。 –

回答

2

onDestroy()只會在活動完成/銷燬/從堆棧中移除時纔會調用。當你移出活動onStop()將被調用。如果您需要保留當前設計,請致電onStop()注意:當前活動的onStop將在新/下一個活動的onCreate/onRestart之後調用。

如果你有一個單一的數據庫,你可以使用SQLiteOpenHelper類由pawelieba 提到你也可以在應用程序類的sqlite的分貝參考,你可以只使用在所有活動中的參考,像

((MyApplication)getApplication()).db

只需在應用程序類的onCreate()中打開數據庫,然後在onTerminate()中關閉它。

你也可以看看這個錯誤的其他SO答案。它曾經被問過很多次。

java.lang.illegalstateexception database not open android

Android java.lang.IllegalStateException database already closed

Android insert the data SQLite error Caused by java.lang.IllegalStateException: database not open

+0

非常感謝@ Atrix1987,我會嘗試你的解決方案。 –

1

SQLite數據庫具有原生界面,通過SQLiteDatabase訪問 - 這個類負責同步從不同的線程本地SQLite的訪問。
SQLiteDatabase被緩存在SQLiteOpenHelper中,它負責提供SQLiteDatabase的實例,它是單例模式。

根據我的經驗,你應該有一個SQLiteOpenHelper的實例,並從中緩存SQLiteDatabase。那麼你不需要關心關閉/打開SQLiteDatabase

該應用程序的一個實例SQLiteOpenHelper需要在應用程序中有單個實例SQLiteDatabase。它將解決多線程訪問本地數據庫的問題。

簡而言之:您從中獲取每個查詢的數據庫的單身人士(SQLiteOpenHelper)。
我正在使用Roboguice來處理醜陋的單例模式。

+0

謝謝@pawelzieba。好的,所以我必須在每個需要訪問數據庫的活動中創建一個新的SQLiteOpenHelper對象?對? –

+0

不,我的意思是爲整個應用程序創建一個「SQLiteOpenHelper」單例。在你的情況下,最簡單的方法可能是在'android.app.Application'類中實現它,我想。 – pawelzieba

+0

好的,所以我必須使用類似於這個:http://nerdwa.com/index.php/2011/09/database-sqliteopenhelper-singleton-class-for-android/,然後instanciate對象時,我需要? –

1

我曾在一個項目中遇到過類似的問題。

該項目使用了一個數據訪問層(DAL),它是一個抽象類,具有用於從只讀數據庫檢索數據的靜態方法。這些方法打開了數據庫,檢索了數據並關閉了數據庫。這會導致數據庫關閉時引發異常。並非總是在所有手機上。

當我實施content provider並用它代替DAL時,問題就消失了。

+0

非常感謝您的建議。我會看看這個,並嘗試幾天,看看是否有任何錯誤。 –

0

一定

  • 接近cusor後,查詢到從sqlite的獲取數據。

  • 在update中使用事務,插入到sqlite中。

但有些時候,也許我們使用許多JOIN查詢序列,它創造廟臺進行查詢,也許它並沒有立即關閉