79

私はAndroidの初心者で、基本的な経験を積むために簡単なアプリケーションに取り組んでいます。私のアプリは非常にシンプルで、ブロードキャスト レシーバーといくつかのアクティビティで構成されています。どちらのコンポーネントも単一のデータベースを使用するため、理論的には、両方が同時にデータベースにアクセスしようとする可能性があります。

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

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

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

そうでなければ、より良い選択肢は何でしょうか? コンテンツ プロバイダーの使用について読んだことがありますが、これには多すぎるでしょう。また、データを他のアクティビティと共有することに興味がありません。私は確かにこの投稿を読んで、かなり役に立ちました。

4

2 に答える 2

101

ここをクリックして、この件に関する私のブログ投稿をご覧ください。


以下は、考えられる 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: SQLite データベースを「ContentProvider」で抽象化する

これが私が提案するアプローチです。1 つは、新しいCursorLoaderクラスはs を必要とするため、Activity または Fragment を で実装しContentProviderたい場合(これを利用することをお勧めします。魔法のようです!)、アプリケーションに を実装する必要があります。さらに、ContentProvider を使用してシングルトン データベース ヘルパーを作成することについて心配する必要はありません。アクティビティから呼び出すだけで、システムがすべて処理してくれます (つまり、複数のインスタンスが作成されるのを防ぐためにシングルトン パターンを設計する必要はありません)。LoaderManager.LoaderCallbacks<Cursor>CursorLoaderContentProvidergetContentResolver()

お役に立てれば!

于 2012-02-14T23:55:22.683 に答える
22

Androidでシングルトンを使用してdbにアクセスすることについて読んだことはありません。それについてのリンクを提供してもよろしいですか。

私のアプリでは、シングルトンではなく単純な dbhelper オブジェクトを使用しています。これは、Android クラスの仕事ではなく、db がロックされないようにするための SQL エンジンの仕事だと考えていました。中型です。

更新#1:あなたが与えた参照を見ると、問題は a の異なるインスタンスを使用することではないようdbhelperです。1 つのインスタンスでも、データベースへのアクセスで問題が発生する可能性があります。問題は同時アクセスに起因します。したがって、異なるスレッドによるデータベースへの適切なアクセスを保証する唯一の方法は、単純なスレッド同期メカニズム (synchronizedメソッドまたはブロック) を使用することであり、シングルトンの使用とはほとんど関係ありません。

更新#2:提供する2番目のリンクは、複数のスレッドがdbに同時に書き込みを行う場合、シングルトンdbhelperオブジェクトが必要であることを明確に示しています。これは、たとえば AsyncTasks から SQL 操作 (挿入/更新/削除) を行う場合に発生する可能性があります。その場合、シングルトン オブジェクトの dbhelper は、単純にすべての SQL 操作をある種のパイプラインに入れ、それらを順番に実行します。

このソリューションは、Java で同期メソッドを使用して適切なスレッド同期を使用するよりも実装が簡単です。実際、この問題について Android ドキュメントのどこかでもっと強調すべきだと思います。シングルトン db ヘルパーの使用が推奨される可能性があります。

この素敵な質問とフォローアップをありがとう。

于 2011-08-01T23:17:31.877 に答える