Eurig Jones
Eurig Jones

Reputation: 8543

SQLiteException: error code 5: database is locked. When accessing ContentProvider from AsyncTask

Quite frequently I get the following exception and I'm really entirely sure what to do about it.

java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:200)
    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
    at java.lang.Thread.run(Thread.java:1019)
Caused by: android.database.sqlite.SQLiteException: error code 5: database is locked
    at android.database.sqlite.SQLiteStatement.native_execute(Native Method)
    at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:61)
    at android.database.sqlite.SQLiteDatabase.delete(SQLiteDatabase.java:1704)
    at azurewing.android.db.provider.NotificationProvider.delete(NotificationProvider.java:80)
    at azurewing.android.db.provider.Provider.delete(Provider.java:87)
    at azurewing.android.db.provider.NotificationProvider.delete(NotificationProvider.java:1)
    at android.content.ContentProvider$Transport.delete(ContentProvider.java:234)
    at android.content.ContentResolver.delete(ContentResolver.java:692)
    at azurewing.android.db.table.NotificationTable.removeAllNotifications(NotificationTable.java:89)
    at azurewing.android.sync.SyncReceiver$1$1.doInBackground(SyncReceiver.java:52)
    at azurewing.android.sync.SyncReceiver$1$1.doInBackground(SyncReceiver.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:185)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
    ... 4 more

I am accessing a ContentProvider (NotificationProvider here) via an AsyncTask. The ContentProvider uses a database of course.

@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
{
    SQLiteDatabase  db = database.getWritableDatabase();
    int numDeleted = database.delete(NotificationTable.TABLE_NAME, selection, selectionArgs);
    return numDeleted;
}

I'm a bit stumped about what to do here. It's clearly a threading issue I think, so I'm thinking of everytime I get the database, I do it from a synchronized method in 1 class. Is this a good idea?

Upvotes: 1

Views: 6694

Answers (1)

CommonsWare
CommonsWare

Reputation: 1007359

Either:

  • Consolidate those to be one provider with one SQLiteOpenHelper, comparing the Uri values to see which set of logic to go through, or

  • Create four separate databases, one per provider/SQLiteOpenHelper, or

  • Have a singleton SQLiteOpenHelper that all four providers share

SQLite threading in Android is managed by SQLiteDatabase. You need exactly one instance of a SQLiteDatabase that all threads share for this to work. If you are using SQLiteOpenHelper, this usually means that you use exactly one instance of SQLiteOpenHelper, since it wraps the SQLiteDatabase.

Upvotes: 6

Related Questions