What would be considered the best practices when executing queries on an SQLite database within an Android app?
Is it safe to run inserts, deletes and select queries
Having had some issues, I think I have understood why I have been going wrong.
I had written a database wrapper class which included a close()
which called the helper close as a mirror of open()
which called getWriteableDatabase and then have migrated to a ContentProvider
. The model for ContentProvider
does not use SQLiteDatabase.close()
which I think is a big clue as the code does use getWriteableDatabase
In some instances I was still doing direct access (screen validation queries in the main so I migrated to a getWriteableDatabase/rawQuery model.
I use a singleton and there is the slightly ominous comment in the close documentation
Close any open database object
(my bolding).
So I have had intermittent crashes where I use background threads to access the database and they run at the same time as foreground.
So I think close()
forces the database to close regardless of any other threads holding references - so close()
itself is not simply undoing the matching getWriteableDatabase
but force closing any open requests. Most of the time this is not a problem as the code is single threading, but in multi-threaded cases there is always the chance of opening and closing out of sync.
Having read comments elsewhere that explains that the SqLiteDatabaseHelper code instance counts, then the only time you want a close is where you want the situation where you want to do a backup copy, and you want to force all connections to be closed and force SqLite to write away any cached stuff that might be loitering about - in other words stop all application database activity, close just in case the Helper has lost track, do any file level activity (backup/restore) then start all over again.
Although it sounds like a good idea to try and close in a controlled fashion, the reality is that Android reserves the right to trash your VM so any closing is reducing the risk of cached updates not being written, but it cannot be guaranteed if the device is stressed, and if you have correctly freed your cursors and references to databases (which should not be static members) then the helper will have closed the database anyway.
So my take is that the approach is:
Use getWriteableDatabase to open from a singleton wrapper. (I used a derived application class to provide the application context from a static to resolve the need for a context).
Never directly call close.
Never store the resultant database in any object that does not have an obvious scope and rely on reference counting to trigger an implicit close().
If doing file level handling, bring all database activity to a halt and then call close just in case there is a runaway thread on the assumption that you write proper transactions so the runaway thread will fail and the closed database will at least have proper transactions rather than potentially a file level copy of a partial transaction.