15

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?

Community
  • 1
  • 1
cmoaciopm
  • 1,686
  • 1
  • 19
  • 29
  • 2
    That's an old thread but still relevant on Google so here's a reference to the correct answer: http://stackoverflow.com/questions/4547461/closing-the-database-in-a-contentprovider – Pedro Andrade Jan 04 '13 at 20:12
  • I think this is the best answer, thanks. – cmoaciopm May 21 '13 at 08:30
  • Read this great Explanation and there is no need to close the db while using contentProvider .. http://stackoverflow.com/questions/14002022/android-sq-lite-closed-exception/25379071#25379071 – AndroidGeek Aug 19 '14 at 08:44

2 Answers2

7

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.

Tarun
  • 13,357
  • 8
  • 39
  • 57
6

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.

hovanessyan
  • 30,591
  • 7
  • 54
  • 75
  • Thanks hovanessyan! But what troubles me is my app support multi thread, I don't know "when" the database is really not needed by the app. The second problem is : what i am facing is ContentProvider(maybe ContentResolver will be exact), from layer design point, i can not get the reference of SQLiteDatabase or SQLiteOpenHelpers easilly. I hate ContenProvider concept! – cmoaciopm Dec 16 '11 at 09:50
  • if you're using separate threads for the DB calls, I assume you will be using AsyncTasks. If that's the case you do all operations in doInBackground() and you close objects in onPostExecute(). I could not understand the other problem. Can you elaborate on this layer design point>? – hovanessyan Dec 16 '11 at 09:52
  • 1
    I have tried the logic like your suggestion, but got exception like "database already closed". I think code execute seq like below:1. thread A getWritableDatabase(); 2. thread B close database; 3. thread A execute sql query and exception happened! – cmoaciopm Dec 16 '11 at 10:02
  • why not have one thread for all DB operations? AsyncTasks does handle threading automatically for you. – hovanessyan Dec 16 '11 at 10:04
  • 1
    yeah, I thinks this method will be ok. But what if I must use ContentProvider/ContentResolver, not the database reference directly? – cmoaciopm Dec 16 '11 at 10:18
  • you can still call getContentResolver() using your Activity context inside AsyncTask, you just have to declare the AsyncTask as inner class in your Activity. – hovanessyan Dec 16 '11 at 11:38