My Android App has a SQLite Database and a Content Provider. This Content Provider is registered in the app's AndroidManifest.xml. It is not exported, so only my app can see it.
As part of resetting the user's profile, I want to completely wipe this database and re-create it from scratch. At first I tried calling deleteDatabase() from the activity's context. This works, but only if the app is closed and reopened afterward. Otherwise it will crash when I attempt to insert rows saying the database is read-only. My understanding is the connection needs to be closed first before calling deleteDatabase(). Yet, the connection is managed by the Content Provider and shouldn't be manually closed, as far as I understand.
As an alternative, I am using the call() method from the ContentResolver to call a custom function that will delete all of the data in the tables and reset the sequence counts manually.
This works, but now I have to delete the data from each table manually and will have to keep track of any changes I make in the future.
Is there a better way to delete the entire database and have the onCreate() of my DatabaseHelper (SQLiteOpenHelper) trigger when using a ContentProvider?
One suggestion that comes to mind is to have your custom function drop the tables and recreate them. You already have the code to create the tables in onCreate() of DatabaseHelper. Refactor this somewhere that is accessible by both DatabaseHelper and the custom method.
Related
I have an android application in which I am using Content Provider on top of the database. However, I see that database gets created only when I insert the first record in the database through the Insert of Content Provider. In this scenario, if there's an error in database creation that would remain pending till the insertion of a record.
I would like to know if there's a way I can create the database when the app is accessed for the first time, so, any possible errors in the database creation appear at the earlier stage.
Within our app we show a splash screen specifically for the purpose of creating the db and initialising some application singletons. I'd recommend something similar.
You can start a db (on)Create or db (on)Upgrade by calling SQLiteDatabase#getWritableDatabase or equivalent. Remember to perform this on a background thread and use standard eventing / callbacks to understand when this (synchronous) method has completed.
If something goes wrong then you can catch that exception during start-up although you can't really recover by the sounds of it so you'll be best off not catching any exceptions and making sure your critical init code is bullet proof.
Ive done a lot of Googlig on this topic and I'm confused as to best practice.
Initially I had:
A) Created a DataBase object in my main class header area and then just passed it to functions as needed. I then later read that a DataBase should be opened and closed each time before use.
so then I:
B) went to each function (passing Context) which uses a SQL command and created a new DataBase object, created a filled cursor via SQL, and then closed the Database before returning. However, I then later read that it's expensive to do this.
now i'm thinking that:
C) I should create a new Database object in each subclass that uses one, and open and close it as needed.
Im sorry for the noob and seemingly design question (delete it if it's out of scope of StackOverflow), however, I truly am confused of how this should be handled to avoid errors, and how Google wants us to do it.
Regards
The Android docs recommend using an SQLiteOpenHelper, which caches the database object. From the SQLiteOpenHelper reference:
Once opened successfully, the database is cached, so you can call this
method every time you need to write to the database. (Make sure to
call close() when you no longer need the database.)
So, I'd go for a singleton carrying an instance of SQLiteOpenHelper, so you can access it from anywhere. Then get the database where you need it, and close it on exit points of your application (if any). That way you only open a database if required, but can re-use the same connection for other tasks as well.
If you do only need the database for single tasks and/or there are other Applications accessing the same database, you may consider closing it directly after your database-tasks are done; there is a discussion about closing in another question.
This title may sound a little bit crazy, but this is what is making me confused. My app heavily uses local database operations. As suggested in the Android docs and some blogs, I extended the SQLiteOpenHelper class and defined all my DB operations there. As some of my DB operations execute in threads, opening and closing of the db causes some IllegalStateExceptions. So, I made my DB helper as Singleton and it resolved those issues, also getting rid of the open and close operations for every DB action. Now everything seems to be working fine even though I never close the DB.
My confusion is that is it necessary to close DB?
If so, what is the right place to do so, is it in onDestroy of the main activity or somewhere else?
If I don't close DB, what are the side effects?
You can catch IllegalStateException if you'll try to open again the same database.
If you create instance of DBHelper in onCreate method of main activity - it would be write to close db in onDestroy. So, you can be sure, that next time in onCreate your database is not opened already.
If you have reference to DBHelper in service, than it should be opened and closed in service, and not in activity.
You can also use Application class for opening db, but than it will opened every time when you app starts (for example when you receive BroadcastReceiver)
The reason why you get exceptions is that you are trying to write/read from the same database via different threads.
I believe the best place to close your database would be inside the onDestroy() of your mainActivity.
I faced same problem.I opened database ,perform some operation and i forget to close.Actually i saw some exceptions i logcat that is "Leak found" db is opened and never closed.
In my android app, I use SQLiteOpenHelper to implements ContentProvider.
Query, add, delete operations are all through ContentProvider.
But in one of my android phone(htc g13), I found *.db-wal file in directory /data/data/[package name]/databases. And the file size increate very fast when operating with ContentProvider. It occupied user RAM space too much.
It is recommended to close the SQLiteOpenHelper to solve my problem (it is useful) in post enter link description here.
But I want to find a "place" to add the "close()" method since I am not using SQLiteOpenHelper directly (using through ContentProvider). query() method in ContentProvider must return a Cursor, and SQLiteDatabse should stay in open state.
I'm confused, what show I do now to keep *.db-wal gone and use ContentProvider normally?
Android framework engineer defer to this view that you need to close the DB.
As per Dianne Hackborn(Android Framework Engineer) in this thread:
A content provider is created when its hosting process is created, and
remains around for as long as the process does, so there is no need to
close the database -- it will get closed as part of the kernel
cleaning up the process's resources when the process is killed.
You have a couple of cases to cover:
1) When your application finishes (e.g. entering onDestroy()) make sure you close all Cursors, Database instances of SQLiteDatabase and SQLiteOpenHelpers (using the model if (connection.isOpen()) object.close())
2) When you application goes onPause() -> onResume() - use this stages appropriately to pause/resume your connection or to close/open them.
It's a good practice to close your database immediately after you finish working with it. The database is cached, so there's no problem closing it and re-acquire instance again when you need it with getWritableDatabase()/getReadableDatabase()
From the official doc:
"Once opened successfully, the database is cached, so you can call this method every time you need to write to the database. (Make sure to call close() when you no longer need the database.)"
Also keep in mind that if SQLiteOpenHelper caches and tracks all open instances of SQLiteDatabase, it basically means that if you don't leave open database connections, you won't have to call close on SQLiteOpenHelper.
I recommend closing all cursors and databases immediately after you stop working with them. Always try to enforce try/catch/ for queries operations and a "finally block" to call the close methods on the objects.
I'm working with SQLite in my android project. There is a feature that is clear to me -- if there are multiple threads working with DB then they should use only ONE instance of DBHelper and SQLite guarantee a safe access (even if it is concurrent) to the DB.
But I still have one thing needed to be clarified. How should I manage with DB connection (SQLiteDatabase object)? How often should I call geWritableDatabase() and close()? Is it ok if I call these methods once? Or it's better to obtain SQLDatabase object and close one every time I perform read/write operation on DB?
It is handled by default... I mean if a writtable database open, whenever you try to access read-only database it closes writtable one and create new read-only database instance. As far as i know :)