Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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.</p> <p>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. </p> <p>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.</p> <p>I chose the second option and derived a cursor by extending the SQLiteCursor class and implementing the SQLiteDatabase.CursorFactory interface with the following code:</p> <pre><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 </code></pre> <p>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.</p> <p>These two classes are nested inside of MyProvider, my content provider class and the data member CursorID is initialized by MyProvider.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload