Android SQLite просочился
i проблема с обработчиком sql
A SQLiteConnection object for database '/data/data/.../databases/queueManager' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.
взятый из учебника Androidhive и настроенный для моего использования
таблица выглядит как
+ ----------------------------------------------------------- +
: DATABASE_ID : DATABASE_QID : DATABASE_QUEUE : DATABASE_DATE :
+ ----------------------------------------------------------- +
Код
DBQueue searchDBqid(int id) {
SQLiteDatabase db = this.getReadableDatabase();
String selectQuery = "SELECT * FROM " + TABLE_QUEUE + " WHERE " + DATABASE_QID + " = " + id;
Cursor cursornum = db.rawQuery(selectQuery, null);
int dk = cursornum.getCount();
cursornum.close();
if (dk >0) {
Cursor cursor = db.query(TABLE_QUEUE, new String[] { DATABASE_ID,
DATABASE_QID, DATABASE_QUEUE, DATABASE_DATE }, DATABASE_QID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null) cursor.moveToFirst();
DBQueue dbqueue = new DBQueue(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2), cursor.getString(3));
return dbqueue;
}
db.close();
return null;
}
DBQueue getDBQueue(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_QUEUE, new String[] { DATABASE_ID,
DATABASE_QID, DATABASE_QUEUE }, DATABASE_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
DBQueue dbqueue = new DBQueue(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2), cursor.getString(3));
return dbqueue;
}
public String getAllqid() {
Time today = new Time(Time.getCurrentTimezone());
today.setToNow();
String selectQuery = "SELECT * FROM " + TABLE_QUEUE + " WHERE " + DATABASE_DATE + " = '" + today.format("%d %m %Y") + "'";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
StringBuilder sb = new StringBuilder();
if (cursor.moveToFirst()) {
do {
if (sb.length() > 0) sb.append(',');
sb.append(cursor.getString(1));
} while (cursor.moveToNext());
}
String result = sb.toString();
return result;
}
public void deleteDatedDBQueue() {
Time today = new Time(Time.getCurrentTimezone());
today.setToNow();
String selectQuery = "SELECT * FROM " + TABLE_QUEUE + " WHERE " + DATABASE_DATE + " != '" + today.format("%d %m %Y") + "'"; ;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor.moveToFirst()) {
do {
db.delete(TABLE_QUEUE, DATABASE_ID + " = ?",
new String[] { String.valueOf(Integer.parseInt(cursor.getString(0))) });
} while (cursor.moveToNext());
}
db.close();
}
public int getDBQueueCount() {
String countQuery = "SELECT * FROM " + TABLE_QUEUE;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
cursor.close();
return cursor.getCount();
}
}
Может кто-нибудь скажет мне, как исправить эту утечку?
полный код: http://ijailbreak.me/databasehandler.txt
Ответы
Ответ 1
Каждый Cursor
должен быть закрыт, когда вы закончите с ним. Традиционный способ сделать это:
Cursor cursor = db.query(...);
try {
// read data from the cursor in here
} finally {
cursor.close();
}
Но теперь, try-with-resources, это может быть гораздо более кратким:
try (Cursor cursor = db.query(...)) {
// read data from the cursor in here
}
Ответ 2
Вы забыли закрыть свои курсоры несколько раз, убедитесь, что вы всегда закрываете курсор, когда делаете.
Например, второй запрос не закрывает курсор, у меня есть TODO'd для ясности
Также вы не закрываете SQLiteDatabase
после того, как вы сделали это в getDBQueue
, getAllqid
и getDBQueueCount
, если вы измените свой дизайн, чтобы сделать ваш SQLiteOpenHelper
синглтон, тогда вам не нужно будет закрывать SQLiteDatabase
и избежать утечки
DBQueue searchDBqid(int id) {
SQLiteDatabase db = this.getReadableDatabase();
String selectQuery = "SELECT * FROM " + TABLE_QUEUE + " WHERE " + DATABASE_QID + " = " + id;
Cursor cursornum = db.rawQuery(selectQuery, null);
int dk = cursornum.getCount();
cursornum.close();
if (dk >0) {
// TODO: Close this cursor!
Cursor cursor = db.query(TABLE_QUEUE, new String[] { DATABASE_ID,
DATABASE_QID, DATABASE_QUEUE, DATABASE_DATE }, DATABASE_QID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null) cursor.moveToFirst();
DBQueue dbqueue = new DBQueue(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2), cursor.getString(3));
return dbqueue;
}
db.close();
return null;
}
Ответ 3
Каждый раз, когда вы открываете базу данных (читаемую или записываемую), а курсор, который использует ресурсы памяти, должен быть освобожден, используя ".close();" после его использования заканчивается в каждой функции базы данных
например:
if (cursor != null) cursor.moveToFirst();
DBQueue dbqueue = new DBQueue(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2), cursor.getString(3));
return dbqueue;
}
cursor.close();
db.close();
return null;
}
DBQueue getDBQueue(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_QUEUE, new String[] { DATABASE_ID,
DATABASE_QID, DATABASE_QUEUE }, DATABASE_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
DBQueue dbqueue = new DBQueue(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2), cursor.getString(3));
cursor.close();
db.close();
return dbqueue;
}
и т.д....!!
Ответ 4
открыть базу данных в первый раз и последний раз поставить этот код.
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
mdb.close();
super.onDestroy();
}