1

私はAndroid開発に比較的慣れておらず、ac#のバックグラウンドを持っているため、戦略全体が間違っている可能性は十分にありますが、データベース接続を適切に閉じていないためメモリリークが発生しているという警告をEclipseから継続的に受けています。

私は拡張する基本データベースクラスを持っていますSQLiteOpenHelper:

public class MySQLiteOpenHelper extends SQLiteOpenHelper {

    public MySQLiteOpenHelper(Context context, String name,
            CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    public MySQLiteOpenHelper(Context context) {
        this(context, "myDb", null, 1);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE MyTable (A INT)");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public Cursor executeSelect(String sql, String[] parameters) {
        return getReadableDatabase().rawQuery(sql, parameters);
    }

}

一般的なエンティティ:


public class MyClass {
    private int a;

    public void setA(int value) {
        this.a = value;
    }

    public int getA() {
        return this.a;
    }
}

そして本質的にはサービスですMyClass(ただし、実際にはこれは再利用性のために汎用抽象クラスを拡張します)


public class MyClassService {

    private MySQLiteOpenHelper helper;
    private Context context;

    public MyClassService(Context context) {
        this.context = context;
    }

    private MySQLiteOpenHelper getHelper() {
        if (helper == null) {
            helper = new MySQLiteOpenHelper(this.context);
        }
        return helper;
    }

    public void dispose() {
        if (helper != null) {
            helper.close();
            helper = null;
        }
    }
    public ArrayList<MyClass> getAll()
    {
        ArrayList<MyClass> list = new ArrayList<MyClass>();
        Cursor cursor = getHelper().executeSelect("SELECT A FROM MyTable", new String[0]);

        while (cursor.moveToNext()) {
            MyClass item = new MyClass()
            item.setA(cursor.getInt(0));
            list.add(item);
        }
        cursor.close();
        return list;
    }
}   

だから、私の質問は、アクティビティから次のようなコード行を使用するときです:

ArrayList<MyClass> list = new MyClassService(this).getAll();

すぐに破棄されたインスタンスであるMyClassServiceか、これがメモリ リークの原因である可能性があります。

dispose メソッドを使用してデータベースを確実に閉じるには、完全なコードを呼び出したほうがよいでしょうか?

MyClassService svc = new MyClassService(this);
ArrayList<MyClass> list = svc.getAll();
svc.dispose();
4

3 に答える 3

1

ガベージ コレクターは、クラスだけでなくクラスも収集できます。これは、これらがオブジェクト チェーンHelperの一部でなくなったためです(専門用語ではなく、私が作ったものです)。ただし、データベースを明示的に閉じる必要があります (そうしないと、間違いなくメモリ リークの原因になります)。現状では、ガベージ コレクション中に呼び出されるオブジェクトのメソッドでこれを行うことができます。finalize()

@Override
public void finalize() {
    dispose();
}

しかし、私は通常、少し違うことをすることを好みます。このようなデータ ストアは、複数のクラスからアクセスされる可能性があるため、 Singletonとして記述するのが最適です。異なるインスタンスが作成された場合でも、書き込みを読み取るための新しいアクセス ポイントが開かれ、多くの問題が発生する可能性があります。コードに変数が 1 つあるという点で、シングルトン スタイルのセットアップのようなものがありますが、単にクラスをシングルトンhelperにしたい場合があります。Helperこれを行うには、コンストラクターを削除してこれを追加します。

private static MySQLiteOpenHelper self;

private MySQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
    super(context, name, factory, version);
}

private MySQLiteOpenHelper(Context context) {
    this(context, "myDb", null, 1);
}

public static MySQLiteOpenHelper sharedHelper(Context context) {
    if (self == null)
        self = new MySQLiteOpenHelper(context);
    return self;
}

MyClassService次に、を使用してヘルパー オブジェクトを追跡する代わりに、以下を使用getHelper()して THE ヘルパーを取得できます。

MySQLiteOpenHelper.sharedHelper(context);

これを行う利点は、アプリ全体で 1 つのヘルパーを追跡するだけでよく、ヘルパーのfinalize()メソッドでデータベースを閉じることができることを意味します。これは、アプリ プロセスが強制終了されたときに呼び出され、メモリ リークを防ぎます。

public void finalize()
{
    close();
}
于 2013-04-26T17:15:10.050 に答える