虽然一切都关闭了,但SQLite Connection泄露了

时间:2013-08-09 13:05:46

标签: android android-sqlite sqliteopenhelper

我找到了很多像close the connectionclose 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连接泄露警告。

我做错了什么?

3 个答案:

答案 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();
 }