Połączenie SQLite wyciekło, chociaż wszystko jest zamknięte

Znalazłem wiele rzeczy takich jak close the connection i close the cursor, ale robię to wszystko. Mimo to połączenie SQLite przecieka i dostaję takie Ostrzeżenie:

A SQLiteConnection object for database was leaked!

Mam menedżera baz danych, który nazywam w moich działaniach następującym kodem:

DatabaseManager dbm = new DatabaseManager(this);

Kod mojej klasy menedżera baz danych następuje teraz:

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

Kiedy wywołuję metodę bazodanową, robię następujące rzeczy:

public Object getData() {

    open();

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

    close();

    return data;
}

Ale jak już mówiłem, nadal dostaję ostrzeżenie o wycieku połączenia SQLite.

Kim jestem źle robisz?

Author: sjas, 2013-08-09

2 answers

Pogrubiona czcionka w cytacie odpowiada tej części Twojego kodu:

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

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

Podejście # 1: Użyj abstrakcyjnej fabryki, aby utworzyć instancję SQLiteOpenHelper

Zadeklaruj swój Pomocnik bazy danych jako statyczną zmienną instancji i użyj Abstrakcyjny wzór fabryczny gwarantujący własność Singletona. Na przykładowy kod poniżej powinien dać ci dobry pomysł o tym, jak przejść poprawne zaprojektowanie klasy bazy danych.

Statyczna metoda getinstance zapewnia, że tylko jeden Baza danych zawsze będzie istnieć w danym momencie. Jeśli mInstance obiekt nie został zainicjowany, zostanie utworzony. Jeśli ktoś ma już został utworzony, a następnie po prostu zostanie zwrócony.

powinieneś nie inicjalizuje obiektu pomocniczego używając z new DatabaseHelper(context).
Zamiast tego Zawsze używaj DatabaseHelper.getInstance(context), ponieważ gwarantuje że tylko jeden Pomocnik bazy danych będzie istniał w całym cyklu życia aplikacji.

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);
  }
}
 120
Author: sjas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-23 10:33:16
private void method() {
        Cursor cursor = query();
        if (flag == false) {  // WRONG: return before close()
            return;
        }
        cursor.close();
   }

Dobra praktyka powinna wyglądać tak:

    private void method() {
        Cursor cursor = null;
        try {
            cursor = query();
        } finally {
            if (cursor != null)
                cursor.close();  // RIGHT: ensure resource is always recovered
        }
    }
 1
Author: Avinash Shinde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-23 10:40:28