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;
    }
}   

所以,我的问题是当我在 Activity 中使用这样的代码行时:

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()在垃圾收集期间调用的 Object 方法中执行此操作:

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

然而,我通常更喜欢做一些不同的事情。像这样的数据存储通常最好写成Singletons,因为它们可以被多个类访问,如果创建了不同的实例,它们仍然会打开一个新的访问点来读取写入,并可能导致许多问题。你有一种单例风格的设置,因为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()

MySQLiteOpenHelper.sharedHelper(context);

这样做的好处意味着您只需在整个应用程序中跟踪一个 Helper,并且在 helper 的finalize()方法中,您现在可以关闭数据库。这将在应用程序进程被终止时调用,并防止任何内存泄漏:

public void finalize()
{
    close();
}
于 2013-04-26T17:15:10.050 回答
1

您应该显式调用dispose- 不这样做不会导致内存泄漏(对象可以在之后立即收集,new MyClassService(this).getAll()因为没有对该对象的任何实时引用),但可能会导致您的数据库用尽可用连接。

于 2013-04-26T16:59:21.250 回答
0

您忘记调用close从返回的数据库对象getReadableDatabase()

于 2013-04-26T17:05:00.960 回答