Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sqlite Database LEAK FOUND exception in android?

I am getting this exception in database Leak Found

my LOGCAT Shows this:

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)

how can i solve it???

thanks in advance...

like image 351
Praveen Avatar asked Feb 17 '10 11:02

Praveen


2 Answers

You have to close your database

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

like image 184
Donal Rafferty Avatar answered Nov 15 '22 06:11

Donal Rafferty


You need to either close the database object or hold on to the database object so that there is a variable in your Content Provider that is referencing the database object allowing garbage collection to ignore the open database.

The problem with closing the database in the content provider is that the cursor being returned to the activity that requested the query becomes an empty cursor.

So the choice is to either hold on to the open database object for ever (the life time of the Content Provider) or to make sure that the database is closed when the cursor is closed.

I chose the second option and derived a cursor by extending the SQLiteCursor class and implementing the SQLiteDatabase.CursorFactory interface with the following code:

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

This code provides a cursor object that closes the database when the cursor itself is closed, resolving the IllegalStateException during garbage collection. This does place the responsibility of closing the cursor on the activity that requested it. This should not put an extra burden on the activity since closing the cursor when done with it is good practice.

These two classes are nested inside of MyProvider, my content provider class and the data member CursorID is initialized by MyProvider.

like image 36
Steven F. Le Brun Avatar answered Nov 15 '22 04:11

Steven F. Le Brun