When I get a Cursor back from a sqlite DB query in Android it seems to contain a fixed number of rows that does not change regardless of what happens to the DB. If, for example, some of the rows are deleted while the Cursor is open I can still reference rows that have been deleted. This is nice, but how does it work?
One guess might be that sqlite knows I have a Cursor that is pointing to that row and so keeps a copy of the old data around. But what if I had a million rows, deleted them and replaced them with a million different rows, seems like a lot of data to cache!
UPDATE:
I am now thinking that this caching we see in Android isn’t really bullet-proof and isn’t part of SQLite. I created a test which builds a database with 1,000,000 rows in it, then I queried the db printed out some results and left the cursor open, next I deleted half the rows, finally I tried to access the cursor that I left open and the result is a crash:
04-05 18:17:16.141 E/AndroidRuntime(19655): java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
04-05 18:17:16.141 E/AndroidRuntime(19655): at android.database.CursorWindow.nativeGetLong(Native Method)
04-05 18:17:16.141 E/AndroidRuntime(19655): at android.database.CursorWindow.getLong(CursorWindow.java:507)
04-05 18:17:16.141 E/AndroidRuntime(19655): at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)
04-05 18:17:16.141 E/AndroidRuntime(19655): at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:220)
04-05 18:17:16.141 E/AndroidRuntime(19655): at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:237)
04-05 18:17:16.141 E/AndroidRuntime(19655): at com.jacob.DirectDbActivity$4.run(DirectDbActivity.java:88)
This seems like a bug in Android, since most databases are small the cache window can hold all the results but in large databases this is going to hit you.
Last I checked, a cursor is a snapshot of the database based on the SQL that created it. Much like a Data set. If you change the database the cursors may not know that their snapshot is old. You can perform a re-query on the cursor to get fresh data based on the original SQL that created the cursor.