2012-10-09 51 views
19

我有问题与SQL处理的Android SQLite的泄露

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

回答

50

,当你完成它的每个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 
} 
+0

我也认为它是因为数据库没有关闭的几个方法,这可能意味着当他的开放助手超出范围,它泄漏,所以在我的答案,我建议让开放助手单身,以避免打开/关闭的问题,当他试图跨越多个线程使用它时,情况只会变得更糟:) –

+6

是的,数据库连接应该始终是单例。 –

+0

好的,我每次使用Cursor都使用这种方法。并添加了几个db.close();我认为它解决了这个问题。谢谢 ! – Kirma

8

您忘记关闭几次你的光标,请确保您始终关闭游标当你完成。

例如,第二查询不关闭游标,我已经TODO'd它清晰

你也不要关闭SQLiteDatabase一旦你在getDBQueuegetAllqidgetDBQueueCount做,如果你改变你的设计让你的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; 
    } 
0

第一次打开的数据库和最后把这个代码。

@Override 
     protected void onDestroy() { 
      // TODO Auto-generated method stub 
     mdb.close(); 
     super.onDestroy(); 
     } 
1

每次打开一个数据库时间(读或写),以及使用的存储器资源已经通过使用被解除分配光标“.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; 
    } 

等.... !!