1. ホーム
  2. java

SQLiteDatabaseのSingletonデザインパターンを使用する

2023-08-11 11:20:40

質問

私は Android の初心者で、基本的な経験を得るために簡単なアプリケーションに取り組んでいます。私のアプリは非常に単純で、他のものの間で、放送受信機といくつかのアクティビティで構成されています。両方のコンポーネントが 1 つのデータベースを使用するため、理論的には、両方が同時に DB にアクセスしようとすることが起こり得ます。

現在、私は、必要なときに db オブジェクト (SQLite db ヘルパー クラス) をインスタンス化し、必要な操作 (クエリ、挿入など) を実行するだけです。

私がここや他のドキュメントで読んだところでは、これには、dbが同時にアクセスされた場合に"db locked"例外が発生するという問題があるので、より良いアプローチは、このdbオブジェクトの単一のインスタンスを持ち、すべてのコンポーネントが常に同じdb接続を使用することです。

上記の推論は正しいでしょうか。シングルトンは、このための十分なソリューションでしょうか。一部の純粋主義者はそれに反対するかもしれませんが、これはかなり単純なアプリケーションであるため、他のケースでは行わないことを行う余裕があることに注意してください。

そうでなければ、より良いオプションは何でしょうか?コンテンツ プロバイダーの使用について読みましたが、これには多すぎますし、他のアクティビティとデータを共有することにも興味がありません。私は確かにこれを読みました。 ポスト で、割と参考になりました。

どのように解決するのですか?

この件に関する私のブログ記事はこちらです。


以下は、3つの可能なアプローチを示すサンプルコードです。これらは、アプリケーション全体でデータベースへのアクセスを可能にします。

アプローチ1: `SQLiteOpenHelper` を静的データメンバにする。

これは完全な実装ではありませんが、この方法によって DatabaseHelper クラスを正しく設計するためのヒントになるでしょう。静的なファクトリーメソッドにより、DatabaseHelperのインスタンスは常に1つだけ存在することが保証されます。

/**
 * create custom DatabaseHelper class that extends SQLiteOpenHelper
 */
public class DatabaseHelper extends SQLiteOpenHelper { 
    private static DatabaseHelper mInstance = null;

    private static final String DATABASE_NAME = "databaseName";
    private static final String DATABASE_TABLE = "tableName";
    private static final int DATABASE_VERSION = 1;

    private Context mCxt;

    public static DatabaseHelper getInstance(Context ctx) {
        /** 
         * use the application context as suggested by CommonsWare.
         * this will ensure that you dont accidentally leak an Activitys
         * context (see this article for more information: 
         * http://android-developers.blogspot.nl/2009/01/avoiding-memory-leaks.html)
         */
        if (mInstance == null) {
            mInstance = new DatabaseHelper(ctx.getApplicationContext());
        }
        return mInstance;
    }

    /**
     * constructor should be private to prevent direct instantiation.
     * make call to static factory method "getInstance()" instead.
     */
    private DatabaseHelper(Context ctx) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.mCtx = ctx;
    }
}

アプローチ2: `ContentProvider` を使って SQLite データベースを抽象化する。

これは私が提案するアプローチです。1 つは、新しい CursorLoader クラスでは ContentProvider を実装する必要があるので、アクティビティやフラグメントに LoaderManager.LoaderCallbacks<Cursor> を実装して CursorLoader を実装する必要があります (これは魔法のようなものなので、利用することをお勧めします!)。 ContentProvider を実装する必要があります。さらに、ContentProvidersでSingletonデータベース・ヘルパーを作ることを心配する必要はないでしょう。単に getContentResolver() を呼び出すだけで、システムがすべてを引き受けてくれます(言い換えれば、複数のインスタンスが作られないようにするためのSingletonパターンを設計する必要はないのです)。

お役に立てれば幸いです。