2012-04-26 10 views
1

ローカルSQLiteデータベースで長い削除アクションを実行するAsyncTaskを実行しているときに問題が発生しています。ユーザーが画面を回転させると、AsyncTaskの実行中にActivityが再作成され、データベースへの新しい接続が作成されます。Android SQLiteの並行処理の問題

私は

...削除が行われている間など読みやすいデータベースを開くときに、それがクラッシュし、なぜそう 、私は理解していない、SQLiteのは、一度に複数の読み取りと1回の書き込みをサポートしており、このケースになることを知っています

失敗が次である:

04-26 12:54:21.839: I/Database(3925): sqlite returned: error code = 5, msg = database is locked 
04-26 12:54:21.839: E/Database(3925): SELECT locale FROM android_metadata failed 
04-26 12:54:21.839: E/Database(3925): Failed to setLocale() when constructing, closing the database 
04-26 12:54:21.839: E/Database(3925): android.database.sqlite.SQLiteException: database is locked 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.native_setLocale(Native Method) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.setLocale(SQLiteDatabase.java:1967) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1835) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:820) 
04-26 12:54:21.839: E/Database(3925): at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:197) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:172) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.openReadableDatabaseWithForeignKeySupport(DatabaseManager.java:180) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.open(DatabaseManager.java:157) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.persistence.DatabaseManager.<init>(DatabaseManager.java:147) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.openerp.models.ConnectionProfile$ConnectionProfileManager.<init>(ConnectionProfile.java:138) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.activities.SelectConnectionProfile.fillData(SelectConnectionProfile.java:71) 
04-26 12:54:21.839: E/Database(3925): at com.caumons.trainingdininghall.activities.SelectConnectionProfile.onResume(SelectConnectionProfile.java:66) 
04-26 12:54:21.839: E/Database(3925): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1149) 
04-26 12:54:21.839: E/Database(3925): at android.app.Activity.performResume(Activity.java:3833) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2085) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2110) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1643) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2796) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.access$1600(ActivityThread.java:117) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:932) 
04-26 12:54:21.839: E/Database(3925): at android.os.Handler.dispatchMessage(Handler.java:99) 
04-26 12:54:21.839: E/Database(3925): at android.os.Looper.loop(Looper.java:123) 
04-26 12:54:21.839: E/Database(3925): at android.app.ActivityThread.main(ActivityThread.java:3647) 
04-26 12:54:21.839: E/Database(3925): at java.lang.reflect.Method.invokeNative(Native Method) 
04-26 12:54:21.839: E/Database(3925): at java.lang.reflect.Method.invoke(Method.java:507) 
04-26 12:54:21.839: E/Database(3925): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
04-26 12:54:21.839: E/Database(3925): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
04-26 12:54:21.839: E/Database(3925): at dalvik.system.NativeStart.main(Native Method) 

私は次の回避策をコード化されたが、私は、これは非常に丁寧ではないと思う:

private void openReadableDatabaseWithForeignKeySupport() { 
    try { 
     mDatabase = mDatabaseHelper.getReadableDatabase(); 
     mDatabase.execSQL("PRAGMA foreign_keys = ON"); 
    } catch (SQLiteException e) { 
     /* 
     * If there is an exception because the database is locked, 
     * we will retry until it is free and can be opened. 
     * */ 
     Log.d(getClass().getName(), e.toString()); 
     openReadableDatabaseWithForeignKeySupport(); // Recursive call 
    } 
} 

最も好奇心は失敗しているようだ何のAndroidによって自動的に呼び出さsetLocale()方法であるということですが、docsはと言う:

にsetLocale()がこのデータベースのロケールを設定します。このデータベースにNO_LOCALIZED_COLLATORSフラグが設定されているか、読み取り専用で開いている場合は何も行いません。

ご協力いただければ幸いです。 :)

+0

[SQLite例外:データベースがロックされている問題](http://stackoverflow.com/questions/7657223/sqlite-exception-database-is-locked-issue) –

+0

また、あなたの活動が回転したときに再作成しないようにするには、AndroidManifest.xmlのアクティビティ定義にandroid:configChanges = "keyboardHidden | orientation"を追加できます。 – DustinB

答えて

2

このように定期的にデータベースを開閉するのは良い考えではありません。アプリケーションの起動時に一度開いて、この接続をアプリの生涯を通して再利用してください。あなたはそれを閉じることを気にする必要はありません。 SQLiteは、並行処理を単独で管理するので、複数のスレッドについても心配する必要はありません。

これにより、すべての「データベースがロックされています」というエラーがなくなり、コードをより簡潔かつ簡単にすることができます。

+0

こんにちは!高速回答ありがとう! :)だから、あなたはあなたのデータベースを保持するためにシングルトンを作成するでしょう、そうですか?データベースを閉じないのは悪い習慣ではありませんか? – Caumons

+0

私はすでにこれを実装し、うまくいっています。しかし、私は疑問を持っています...シングルトンのインスタンスを同期するか、必要ではない(実際には変更されていないので)?あなたの答えをありがとう! – Caumons

+0

同期する必要はなく、データベースを閉じる必要はありません。すべてのデータベース書き込みは、できるだけ早い時期にストレージにコミットされるので、それを閉じても効果はありません。 –