9

それで、私はいくつかのアイデアを思いついたので、それが実現可能かどうか疑問に思っています。

複数のテーブル (データベース モデル) があり、それぞれが何らかのクラスで表されているとしましょう。オープン ヘルパーでシングルトン パターンを使用しないので、データベースの単一インスタンスを提供する単純なクラスをいくつか作成しました。アイデアは、すべてのテーブルが SQLiteDatabase (open ヘルパーによって返される) への参照を保持している限り、それらはすべて同じ DB インスタンスで動作し、おそらく open ヘルパーがこれを行うため、作業をデータベースと同期する必要はないということです。最後のテーブルが終了すると、GC がオープン ヘルパーを収集します (最後の参照は弱い参照になるため) -> finalize() が呼び出され、このメソッド中にデータベースを閉じて、OS からの警告を防ぎます。私の質問は次のとおりです:これは機能しますか?DB を自動的に閉じて、リークまたは例外をスローしますか?

これが私のクラスです:

public class DatabaseHelper {

private static WeakReference<SomeCustomOpenHelper> sDBOpenHelper;

private void notifyDBCreate(SQLiteDatabase db) {
    for (DBTable table : mTables) {
        table.onDBCreate(db);
    }
}

private void notifyDBUpgrade(SQLiteDatabase db) {
    for (DBTable table : mTables) {
        table.onDBUpgrade(db);
    }
}

public SQLiteDatabase getDatabase(boolean readOnly) {
    SomeCustomOpenHelper dbHelper = sDBOpenHelper.get();
    if (dbHelper == null) {
        dbHelper = new SomeCustomOpenHelper(context, name, factory, version, new DatabaseEventsCallback());
        sDBOpenHelper = new WeakReference<SomeCustomOpenHelper>(dbHelper);
    }
    if (readOnly) {
        return dbHelper.getReadableDatabase();
    } else {
        return dbHelper.getWritableDatabase();
    }
}

private class DatabaseEventsCallback implements IDatabaseEventsCallback {

    @Override
    public void onCreate(SQLiteDatabase db) {
        notifyDBCreate(db);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db) {
         notifyDBUpgrade(db);
    }

}

interface IDatabaseEventsCallback {
    void onCreate(SQLiteDatabase db);

    void onUpgrade(SQLiteDatabase db);
}

private static class SomeCustomOpenHelper extends SQLiteOpenHelper {

    private IDatabaseEventsCallback mCB;

    public SomeCustomOpenHelper(Context context, String name, CursorFactory factory, int version, IDatabaseEventsCallback cb) {
        super(context, name, factory, version);

        mCB = cb;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        mCB.onCreate(db);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        mCB.onUpgrade(db);
    }

    @Override
    protected void finalize() throws Throwable {
        this.close();
        super.finalize();
    }
}
}
4

5 に答える 5

2

私はプロジェクトに取り組んでいたときに同じ問題を経験しました。また、静的インスタンスが十分なメモリを使用しており、かなりのメモリ リークを引き起こしているのではないかという疑いにも夢中になりました。

弱い参照を作成することで、データベース インスタンスが収集されることが保証されるかどうかはわかりません。ただし、可能な回避策は次のとおりです。すべてのデータベーストランザクションが完了し、データベースを閉じたら、静的データベースインスタンスに null 値を割り当てます。これにより、データベース インスタンスがメモリを割り当てなくなる可能性があります。

これが機能するかどうか、またはより良い回避策があるかどうかを教えてください。

于 2013-04-04T09:56:23.850 に答える
2

答えもよくわからなかったのですが、興味を持って調べてみました。

答えはここに適切に書かれています。 http://blog.foxxtrot.net/2009/01/a-sqliteopenhelper-is-not-a-sqlitetablehelper.html

しかし、基本的に情報の核心は次のとおりです。

各テーブルに 1 つずつ、合計 3 つの SQLiteOpenHelper クラスを作成しましたが、それらはすべて 1 つのデータベース ファイルしか参照していませんでした。

ここですべてがバラバラになりました。Android は、関連付けられているパッケージ、データベースの名前、および指定したバージョン番号に基づいて、データベースのバージョンを維持します。パッケージと名前によって、デバイス上のパスが決定されますが、バージョンはデバイス上の (どこかに) 保存されるため、OpenHelper の onUpgrade イベント ハンドラーをいつ呼び出す必要があるかがわかります。SQLiteOpenHelper コンストラクターで、データベースが既に存在すると判断した場合、呼び出しを行っている特定のクラスが以前に呼び出されたことがなくても、onCreate メソッドまたは onUpgrade メソッドをまったく呼び出しません。

于 2013-03-27T09:01:46.557 に答える
1

あなたはそうすることができます。あなたが言うように、ロックは SQLite で発生するはずであり、その周りの問題は聞いたことがないので、これで問題ないはずです。唯一の制限は、すべてのテーブルを同じデータベースに格納する必要があることです。これは、Android では今のところ 1 つのファイルしか持てないためです。

データベースを閉じることは別のことです。そのため、シングルトン パターンを使用することが実際に興味深い理由です (常に閉じることと開くことを避けます)。それにもかかわらず、あなたのアプローチでは、データベースを使い終わったら必ずデータベースを閉じる必要があります。私に関する限り、これは自動的に行われるわけではありません。

さらに、Lars Vogel は、Android での DB アクセスに関する非常に有用で詳細な記事を書いています。あなたはそこを見てみたいかもしれません。http://www.vogella.com/articles/AndroidSQLite/article.html

于 2013-04-01T21:35:06.687 に答える