我找到了很多像close the connection
和close the cursor
这样的东西,但是我做了所有这些。 SQLite连接仍然泄漏,我收到这样的警告:
A SQLiteConnection object for database was leaked!
我有一个数据库管理器,我在我的活动中用以下代码调用:
DatabaseManager dbm = new DatabaseManager(this);
我的数据库管理器类的代码现在跟随:
public class DatabaseManager {
private static final int DATABASE_VERSION = 9;
private static final String DATABASE_NAME = "MyApp";
private Context context = null;
private DatabaseHelper dbHelper = null;
private SQLiteDatabase db = null;
public static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//create database tables
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//destroy and recreate them
}
}
public DatabaseManager(Context ctx) {
this.context = ctx;
}
private DatabaseManager open() throws SQLException {
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();
if (!db.isReadOnly()) {
db.execSQL("PRAGMA foreign_keys = ON;");
}
return this;
}
private void close() {
dbHelper.close();
}
}
当我调用数据库方法时,我会执行以下操作:
public Object getData() {
open();
//... database operations take place ...
close();
return data;
}
但正如我所说,我仍然得到这个SQLite连接泄露警告。
我做错了什么?
答案 0 :(得分:127)
引文中的粗体字体对应于代码中的这一部分:
private DatabaseManager open() throws SQLException {
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();
来自:http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html
方法#1:使用抽象工厂实例化 SQLiteOpenHelper
将数据库助手声明为静态实例变量并使用 抽象工厂模式保证单例属性。该 下面的示例代码可以让您了解如何进行操作 正确设计DatabaseHelper类。
静态工厂的getInstance方法确保只有一个 DatabaseHelper将在任何给定时间存在。如果是mInstance 对象尚未初始化,将创建一个。如果有的话 已经创建然后它将被简单地返回。
你应该 不使用new DatabaseHelper(context)
初始化您的帮助程序对象。
相反,总是使用DatabaseHelper.getInstance(context)
,因为它只保证一个 数据库助手将在整个应用程序的生命周期中存在。
public static class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
private static final String DATABASE_NAME = "database_name";
private static final String DATABASE_TABLE = "table_name";
private static final int DATABASE_VERSION = 1;
public static DatabaseHelper getInstance(Context ctx) {
// Use the application context, which will ensure that you
// don't accidentally leak an Activity's context.
// See this article for more information: http://bit.ly/6LRzfx
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(ctx, DATABASE_NAME, null, DATABASE_VERSION);
}
}
答案 1 :(得分:1)
private void method() {
Cursor cursor = query();
if (flag == false) { // WRONG: return before close()
return;
}
cursor.close();
}
良好的做法应该是这样的:
private void method() {
Cursor cursor = null;
try {
cursor = query();
} finally {
if (cursor != null)
cursor.close(); // RIGHT: ensure resource is always recovered
}
}
答案 2 :(得分:1)
上面接受的答案的完整示例: 它可能会帮助某人。
助手类:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "sample.db";
private static final int DATABASE_VERSION = 1;
private static DatabaseHelper mInstance;
private DatabaseHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public static synchronized DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
@Override
public void onCreate(SQLiteDatabase db) {
// create table stuff
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
// drop table stuff
onCreate(db);
}
}
活动:
SQLiteDatabase database = DatabaseHelper.getInstance(getApplicationContext()).getWritableDatabase();
Cursor cursor = database.query("query");
if (cursor != null) {
while (cursor.moveToNext()) {
// stuff
}
cursor.close();
database.close();
}