0

I need some help on database and cursor managing. I noticed that, when entering /leaving certain fragments, I get:

W/SQLiteConnectionPool﹕ A SQLiteConnection object for database '+data+data+database' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.

That made me go back from scratch and check what I'm doing and when. I have:

  • a DatabaseHelper class extending SQLiteOpenHelper, with just some methods for creating and updating the db;
  • a DatabaseManager class, extending nothing. I use this, among other things, to keep a single reference to a DatabaseHelper object:

    public class DatabaseManager {
    
        private DatabaseHelper h; //class extending SQLiteOpenHelper
    
        public DatabaseManager(Context c) {
            if (h==null) { 
                h = new DatabaseHelper(c.getApplicationContext()); }
    
        public Cursor query(...) {
            SQLiteDatabase db = h.getReadableDatabase();
            return db.rawQuery(...)
        }
    
        public void closeConnection() {
            SQLiteDatabase db = h.getWritableDatabase();
            db.close();
            h.close();
        }
    }
    
  • in this class, some methods querying the database and returning a Cursor object;

  • in this class, a closeConnection() method, which I'm not really sure of.

I use this class from fragments, calling each time new DatabaseManager(getActivity()). This should not create a new helper reference. Right now I am:

  • calling Cursor.close() as soon as I got the information I wanted from the query;
  • never calling open() on my helper neither on my SQLiteDatabase, although I read somewhere that should be done. When exactly? Why it all works even without calling it?
  • calling manager.closeConnection() in the onStop() method of fragments that make use of my database. As you can see, that calls close on h (a reference to the helper class) and on a readable SQLiteDatabase object. However, I'm not really sure about that, because it closes the helper reference h without making it null, so maybe there are some problems with future calls to new DatabaseManager() ? Maybe dealing with database with a singleton pattern does not require you to call h.close()?

Apart from that, needless to say (that's why I'm asking), when switching through fragments I get the above mentioned warning. What's wrong? What should I do? What does end transactions in progress mean? Should I modify my closeConnection() method, call it in different lifecycle times, or don't call it at all?


After embarrassing issue pointed out by @Selvin, I made h static. Now if I remove any call to closeConnection(), it all works well and I don't get any warnings. That means I'm never calling neither h.close() or db.close(). Is that ok? If not, when should I call it?

natario
  • 24,954
  • 17
  • 88
  • 158
  • *I use this class from fragments, calling each time new DatabaseManager(getActivity()). This should **not create** a new helper reference.* ... **not true** ... – Selvin Apr 07 '15 at 15:41
  • I found that pattern somewhere, will fix it now implementing a `getInstance()` in `DatabaseHelper`. Thank you. – natario Apr 07 '15 at 15:46
  • `private DatabaseHelper h;` should be static ... but still better idea is to make whole DatabaseManager class a singleton or even better ... use ContentProvider ... ConterProvider should help with SQLiteDatabase leaks ... and Loaders API should help with Cursor leaks – Selvin Apr 07 '15 at 15:48
  • @Selvin Apart from ContentProvider, shouldn't just `DatabaseHelper` be a singleton? Why both `DatabaseHelper` and `DatabaseManager` (which basically keeps a single - static, now - reference to the helper)? Should I merge the two? – natario Apr 07 '15 at 15:52

0 Answers0