40

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 接続がリークされているという警告を受け取ります。

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

4

3 に答える 3

144

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

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 をインスタンス化する

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

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

with を使用してヘルパー オブジェクトを初期化しないでくださいnew DatabaseHelper(context)。代わりに、アプリケーションのライフサイクル全体で 1 つのデータベース ヘルパーのみが存在することが保証される
ため、常に を使用 してください。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);
  }
}
于 2013-08-09T14:12:11.163 に答える
3

上記の受け入れられた回答の完全な例: 誰かを助けるかもしれません。

ヘルパー クラス:

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();
 }
于 2019-11-08T08:46:31.050 に答える