android中的Sqlite数据库LEAK FOUND异常?

时间:2010-02-17 11:57:51

标签: android memory-leaks

我在数据库Leak Found

中收到此异常

我的LOGCAT显示了这个:

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)

我该如何解决?

提前感谢...

3 个答案:

答案 0 :(得分:10)

您必须关闭数据库

public DBAdapter open() throws SQLException 
{
    db = DBHelper.getWritableDatabase();
    return this;
}

//---closes the database---    
public void close() 
{
    DBHelper.close();
}

http://www.devx.com/wireless/Article/40842/1763?supportItem=4

答案 1 :(得分:7)

您需要关闭数据库对象或保留数据库对象,以便Content Provider中有一个引用数据库对象的变量,允许垃圾收集忽略打开的数据库。

在内容提供程序中关闭数据库的问题是返回到请求查询的活动的游标变为空游标。

因此,选择是永远保持打开的数据库对象(Content Provider的生命周期),或者确保在光标关闭时关闭数据库。

我选择了第二个选项并通过扩展SQLiteCursor类并使用以下代码实现SQLiteDatabase.CursorFactory接口来派生游标:

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

此代码提供了一个游标对象,该对象在游标本身关闭时关闭数据库,在垃圾回收期间解析IllegalStateException。这确实将光标关闭在请求它的活动上。这不应该给活动带来额外的负担,因为完成它后关闭光标是一种很好的做法。

这两个类嵌套在MyProvider中,我的内容提供者类和数据成员CursorID由MyProvider初始化。

答案 2 :(得分:2)

请确保在退出活动之前始终关闭数据库助手。

db.close();