web-dev-qa-db-ja.com

すべてが閉じているにもかかわらず、SQLite接続がリークしました

私は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接続リーク警告を受け取ります。

私は何を間違えていますか?

35
flp

引用内の太字のフォントは、コードのこの部分に対応しています。

private DatabaseManager open() throws SQLException {
    dbHelper = new DatabaseHelper(context);
    db = dbHelper.getWritableDatabase();

from: http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html

アプローチ#1:抽象ファクトリーを使用してSQLiteOpenHelperをインスタンス化する

データベースヘルパーを静的インスタンス変数として宣言し、Abstract Factoryパターンを使用してシングルトンプロパティを保証します。以下のサンプルコードは、DatabaseHelperクラスを正しく設計する方法についての良いアイデアを提供します。

静的ファクトリgetInstanceメソッドは、常に1つのDatabaseHelperのみが存在することを保証します。 mInstanceオブジェクトが初期化されていない場合は、作成されます。すでに作成されている場合は、単に返されます。

new DatabaseHelper(context)を使用してヘルパーオブジェクトを初期化しないでください。
代わりに、常にDatabaseHelper.getInstance(context)を使用します。これにより、アプリケーションのライフサイクル全体でデータベースヘルパーが1つだけ存在することが保証されます。

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);
  }
}
130
sjas
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
        }
    }
1
Avinash Shinde