web-dev-qa-db-fra.com

La connexion SQLite a fui bien que tout soit fermé

J'ai trouvé plein de trucs comme close the connection et close the cursor, mais je fais tout ça. La connexion SQLite fuit toujours et je reçois un avertissement comme celui-ci:

A SQLiteConnection object for database was leaked!

J'ai un gestionnaire de base de données, que j'appelle dans mes activités avec le code suivant:

DatabaseManager dbm = new DatabaseManager(this);

Le code de ma classe de gestionnaire de base de données suit maintenant:

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

Lorsque j'appelle une méthode de base de données, je fais la chose suivante:

public Object getData() {

    open();

            //... database operations take place ...

    close();

    return data;
}

Mais comme je l'ai dit, je reçois toujours cet avertissement de fuite de connexion SQLite.

Qu'est-ce que je fais mal?

35
flp

La police en gras dans la citation correspond à cette partie de votre code:

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

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

Approche n ° 1: utiliser une fabrique abstraite pour instancier SQLiteOpenHelper

Déclarez votre assistant de base de données en tant que variable d'instance statique et utilisez le modèle Abstract Factory pour garantir la propriété singleton. L'exemple de code ci-dessous devrait vous donner une bonne idée sur la façon de concevoir correctement la classe DatabaseHelper.

La méthode getInstance d'usine statique garantit qu'un seul DatabaseHelper existera à un moment donné. Si l'objet mInstance n'a pas été initialisé, un sera créé. Si un a déjà été créé, il sera simplement retourné.

Vous ne devez pas initialiser votre objet d'assistance en utilisant avec new DatabaseHelper(context).
Au lieu de cela, utilisez toujours DatabaseHelper.getInstance(context), car cela garantit qu'un seul assistant de base de données existera tout au long du cycle de vie de l'application.

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

Les bonnes pratiques devraient être comme ceci:

    private void method() {
        Cursor cursor = null;
        try {
            cursor = query();
        } finally {
            if (cursor != null)
                cursor.close();  // RIGHT: ensure resource is always recovered
        }
    }
1
Avinash Shinde