Vektor88
Vektor88

Reputation: 4930

Downloaded SQLite database and leak warnings

I've made an application that uses a downloaded SQLite database. To retrieve data in it I'm using a ContentProvider. When I need to read the database, I always (I've checked at least five times) use a code like this:

Cursor c = getContext().getContentResolver().query(MyContentProvider.ITEMSURI,
        projection,where,null,null);
if(c.moveToFirst()){
    while(!c.isAfterLast()){
        itemsList.add(cursorToItem(c));
        c.moveToNext();
    }
}
if(c!=null) c.close();

But I keep getting many errors like this (I make a sequence of queries in a for loop):

10-18 13:16:01.709: W/SQLiteConnectionPool(27704): A SQLiteConnection object 
for database '/storage/emulated/0/MyAPP/mydb.sqlite' was leaked!  
Please fix your application to end transactions in progress properly and to 
close the database when it is no longer needed.

What could cause all these warnings? Cursor is always closed and in ContentProvider there's no need to close database.

Code:

This is the class that manages the database:

public class OpenMyDBHelper{

    private static final String DB_NAME = "mydb.sqlite";
    private static final File DB_PATH = new File(
            MyAppFolderManager.getInternalMemoryFolder(), DB_NAME);

    private SQLiteDatabase db;

    public SQLiteDatabase open() {
        db = SQLiteDatabase.openDatabase(DB_PATH.getAbsolutePath(), null,
                SQLiteDatabase.OPEN_READONLY);
        return db;
    }

    public void close() {
        db.close();
    }

}

And this is my ContentProvider subclass:

public class MyContentProvider extends ContentProvider {

    private OpenMyDBHelper db;
    //static paths/Uri definitions....


    private final static int ITEMS = 1;
    private static final UriMatcher sURIMatcher = new UriMatcher(
            UriMatcher.NO_MATCH);
    static {
        sURIMatcher.addURI(AUTHORITY, ITEMS_PATH, ITEMS);
    }

    @Override
    public boolean onCreate() {
        db = new OpenMyDBHelper();
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        Cursor cursor = null;
        SQLiteDatabase database = db.open();
        int uriType = sURIMatcher.match(uri);
        switch (uriType) {
        case ITEMS:
            cursor = database.query(Constants.TABLE_ITEMS,
                    projection, selection, selectionArgs, null,null,
                    null);
            cursor.setNotificationUri(getContext().getContentResolver(), ITEMSURI);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI (" + uri + ")");
        }
        return cursor;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    //It's just a read-only db, I don't need the CUD operations...

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        return 0;
    }
}

Upvotes: 1

Views: 4672

Answers (2)

Lay Leangsros
Lay Leangsros

Reputation: 9296

If you have to use getReadableDatabase many times:

You can use this.close to close your database from leak. Example :

   public String getAdditionalInfo(final int id) {
        yourDB = this.getReadableDatabase();
        Cursor cursor = yourDB.rawQuery(selectQuery, null);
        if (cursor.moveToFirst()) {
            return cursor.getString(0);
        }
        cursor.close();
        this.close();// You add this line
        return "";
    }

Upvotes: 1

CommonsWare
CommonsWare

Reputation: 1007349

What could cause all these warnings?

The fact that you keep re-opening the database. Open the database once, in onCreate(), not on every query() call.

Though, in all honesty, if you are not implementing the full CRUD operations, I'd just dump the ContentProvider, as you are gaining nothing by it. It might also allow you to avoid doing a bunch of query() calls in a loop and significantly improve performance, by using IN operators and such in a SQLite query.

Upvotes: 3

Related Questions