読者です 読者をやめる 読者になる 読者になる

Androidはワンツーパンチ 三歩進んで二歩下がる

Android卵プログラマーの記録ブログ

今度からSQLiteOpenHelperのDatabaseHelperのインスタンス取得はSingletonパターンにするよ・・・

Android

SQLiteDatabaseLockedExceptionなるエラーが出たんですけど、

android.database.sqlite.SQLiteDatabaseLockedException
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:137)
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: android.database.sqlite.SQLiteDatabaseLockedException: database is locked
at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1135)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1086)
at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:241)
at xxxxx my content provider pgm xxxxxxxxxxx.query(xxxxxxxxx.java:181)
at android.content.ContentProvider$Transport.query(ContentProvider.java:178)
at android.content.ContentResolver.query(ContentResolver.java:317)
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

調べていたら、複数のSQLiteOpenHelperインスタンスが同じデータベースにマルチスレッドで
アクセスしているからでした。

参考サイトさま
Android:1つのDBに複数のContentProvider
Androidのデータベース周りでよくわからないエラーが出る
Android - ContentProviderとSQLite
Using Singleton design pattern for SQLiteDatabase

頻繁にDBにアクセスしないプログラムなら大丈夫だろうけど、念のため
今後はシングルトンパターンにしますよ。
(追記)スレッドセーフにするために、getInstance()メソッドはsynchronizedを指定しておくのも忘れてはいけませんね。(@yusukeさまどうもありがとうございました。)

SQLiteOpenHelperのサブクラス

public class DatabaseHelper extends SQLiteOpenHelper {
    private static DatabaseHelper sSingleton = null;

    public static synchronized DatabaseHelper getInstance(Context context) {
        if (sSingleton == null) {
            sSingleton = new DatabaseHelper(context);
        }
        return sSingleton;
    }

    private DatabaseHelper(Context context) {
        super(context, DatabaseManager.DATABASE_NAME, null, DatabaseManager.DATABASE_VERSION);
    }

データベースを使用する側

    private DatabaseHelper mDBHelper;

    @Override
    public boolean onCreate() {
        mDBHelper = DatabaseHelper.getInstance(getContext());
        return true;
    }