2010-02-17 27 views
5

Tôi nhận được ngoại lệ này trong cơ sở dữ liệu rò rỉ Tìm thấyCơ sở dữ liệu Sqlite LEAK FOUND ngoại lệ trong Android?

logcat tôi thấy điều này:

02-17 17:20:37.857: INFO/ActivityManager(58): Starting activity: Intent { cmp=com.example.brown/.Bru_Bears_Womens_View (has extras) } 
02-17 17:20:38.477: DEBUG/dalvikvm(434): GC freed 1086 objects/63888 bytes in 119ms 
02-17 17:20:38.556: ERROR/Database(434): Leak found 
02-17 17:20:38.556: ERROR/Database(434): java.lang.IllegalStateException: /data/data/com.example.brown/databases/BRUNEWS_DB_01.db SQLiteDatabase created and never closed 
02-17 17:20:38.556: ERROR/Database(434):  at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1694) 
02-17 17:20:38.556: ERROR/Database(434):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:738) 
02-17 17:20:38.556: ERROR/Database(434):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:760) 
02-17 17:20:38.556: ERROR/Database(434):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:753) 
02-17 17:20:38.556: ERROR/Database(434):  at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:473) 
02-17 17:20:38.556: ERROR/Database(434):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193) 
02-17 17:20:38.556: ERROR/Database(434):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98) 
02-17 17:20:38.556: ERROR/Database(434):  at com.example.brown.Brown_Splash.onCreate(Brown_Splash.java:52) 
02-17 17:20:38.556: ERROR/Database(434):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 
02-17 17:20:38.556: ERROR/Database(434):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459) 
02-17 17:20:38.556: ERROR/Database(434):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512) 
02-17 17:20:38.556: ERROR/Database(434):  at android.app.ActivityThread.access$2200(ActivityThread.java:119) 
02-17 17:20:38.556: ERROR/Database(434):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863) 
02-17 17:20:38.556: ERROR/Database(434):  at android.os.Handler.dispatchMessage(Handler.java:99) 
02-17 17:20:38.556: ERROR/Database(434):  at android.os.Looper.loop(Looper.java:123) 
02-17 17:20:38.556: ERROR/Database(434):  at android.app.ActivityThread.main(ActivityThread.java:4363) 
02-17 17:20:38.556: ERROR/Database(434):  at java.lang.reflect.Method.invokeNative(Native Method) 
02-17 17:20:38.556: ERROR/Database(434):  at java.lang.reflect.Method.invoke(Method.java:521) 
02-17 17:20:38.556: ERROR/Database(434):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 
02-17 17:20:38.556: ERROR/Database(434):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 
02-17 17:20:38.556: ERROR/Database(434):  at dalvik.system.NativeStart.main(Native Method) 

làm thế nào tôi có thể giải quyết nó ???

cảm ơn trước ...

Trả lời

7

Bạn cần phải hoặc đóng các đối tượng cơ sở dữ liệu hoặc giữ cho các đối tượng cơ sở dữ liệu để có là một biến trong Nhà cung cấp nội dung của bạn đang tham chiếu đến đối tượng cơ sở dữ liệu cho phép thu thập rác để bỏ qua cơ sở dữ liệu mở.

Sự cố khi đóng cơ sở dữ liệu trong nhà cung cấp nội dung là con trỏ được trả về hoạt động yêu cầu truy vấn trở thành con trỏ trống.

Vì vậy, lựa chọn là để giữ cho đối tượng cơ sở dữ liệu mở bao giờ (thời gian sống của nhà cung cấp nội dung) hoặc để đảm bảo rằng cơ sở dữ liệu được đóng khi con trỏ được đóng lại.

tôi đã chọn tùy chọn thứ hai và thu được một con trỏ bằng cách mở rộng các lớp SQLiteCursor và thực hiện các giao diện SQLiteDatabase.CursorFactory với đoạn mã sau:

public class MyCursor extends SQLiteCursor 
{ 
    final SQLiteDatabase mDatabase; 
    final int   mID; 


    public MyCursor(SQLiteDatabase  database, 
        SQLiteCursorDriver driver, 
        String    table, 
        SQLiteQuery   query, 
        int     cursorID) 
    { 
     super(database, driver, table, query); 

     mDatabase = database; 
     mID  = cursorID; 
    } 

    /** 
    * Closes the database used to generate the cursor when the 
    * cursor is closed. Hopefully, plugging the GC Leak detected 
    * when using pure SQLiteCursor that are wrapped when returned 
    * to an Activity and therefore unreachable. 
    */ 
    @Override 
    public void close() 
    { 
     super.close(); 
     if (mDatabase != null) 
     { 
      mDatabase.close(); 
     } 
    } 

    /** 
    * Closes cursor without closing database. 
    */ 
    public void closeForReuse() 
    { 
     super.close(); 
    } 

    @Override 
    public String toString() 
    { 
     return super.toString() + ", ID# " + mID; 
    } 

} // end of MyCursor class 


//======================================================================== 
// Nested Class to create the MyCursor for queries 

class MyCursorFactory implements SQLiteDatabase.CursorFactory 
{ 
    /** 
    * Creates and returns a new Cursor of MyCursor type. 
    */ 
    public Cursor newCursor (SQLiteDatabase  database, 
           SQLiteCursorDriver driver, 
           String    editTable, 
           SQLiteQuery   query) 
    { 
     int cursorID = MyProvider.CursorID++; 

     return new MyCursor(database, 
          driver, 
          editTable, 
          query, 
          cursorID); 
    } 

} // end of MyCursorFactory class 

Mã này cung cấp một đối tượng con trỏ mà đóng cửa cơ sở dữ liệu khi con trỏ chính nó đã đóng, giải quyết IllegalStateException trong khi thu gom rác thải. Điều này đặt trách nhiệm đóng con trỏ trên hoạt động yêu cầu nó. Điều này không nên đặt thêm gánh nặng cho hoạt động kể từ khi đóng con trỏ khi thực hiện với nó là thực hành tốt.

Hai lớp này được lồng vào bên trong MyProvider, lớp nhà cung cấp nội dung của tôi và thành viên dữ liệu CursorID được khởi tạo bởi MyProvider.

+0

Bạn cũng có thể mở rộng CursorWrapper cho cùng một mục đích, phải không? – sehugg

+0

Thực ra, bạn không thể. Lý do là lớp CursorWrapper không cung cấp quyền truy cập vào SQLiteCursor. CursorWrapper là một trình bao bọc thực sự và không cung cấp cho bạn quyền truy cập trực tiếp vào con trỏ mà nó chứa. Để mẹo của tôi hoạt động, bạn cần phải truy cập vào đối tượng cơ sở dữ liệu để đóng nó. Giao diện Con trỏ không cung cấp API này. Do đó, bạn cần phải sửa đổi lớp Cusror có nguồn gốc để thực hiện công việc. –

+0

Bạn sử dụng lớp MyCursor của mình như thế nào? Hàm khởi tạo cần các tham số bổ sung mà bạn không có từ một cuộc gọi đến SqliteQueryBuilder.query trả về một con trỏ thông thường? – kenyee

2

Chỉ cần đảm bảo bạn luôn đóng Trình trợ giúp DB trước khi thoát Hoạt động.

db.close(); 
+0

chúng ta cũng có thể cần phải đóng con trỏ DB. –

Các vấn đề liên quan