我对Android开发相对较新,并且来自ac #background完全有可能我的整个策略都是错误的,但是当我没有正确关闭数据库连接导致内存泄漏时,我不断收到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();
答案 0 :(得分:1)
您应该显式调用dispose
- 不这样做不会导致内存泄漏(可以在new MyClassService(this).getAll()
之后立即收集对象,因为没有对该对象的实时引用),但是可能导致您的数据库用完可用的连接。
答案 1 :(得分:1)
垃圾收集器将能够收集您的类以及Helper
类,因为它们不再是对象链的一部分(不是技术术语 - 只是我编造的东西)。但是,你仍然需要显式关闭数据库(如果你不这样做肯定是你的内存泄漏的罪魁祸首)。就目前而言,您可以在对象的finalize()
方法中执行此操作,该方法在垃圾回收期间调用:
@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,并且在帮助程序的finalize()
方法中,您现在可以关闭数据库。这将在应用程序进程被终止时调用,并防止任何内存泄漏:
public void finalize()
{
close();
}
答案 2 :(得分:0)
您忘记在close
返回的数据库对象上调用getReadableDatabase()
。