Note that there are some explanatory texts on larger screens.

plurals
  1. PO"error code 5: database is locked" when using a ContentProvider
    text
    copied!<p>I have an application that runs an activity with a service in a separate process that is started and bound to the activity. The service contains a handler that posts a runnable to be run after a delay.</p> <p>I want each component to log to the database, so I implemented a content provider that deals with database access and I call it from the service or activity via extended AsyncTask sub-classes.</p> <p>This all works beautifully on the emulator, but when I run it in debug on my phone I get a sporadic database locked error on my database writing: </p> <p><strong>UPDATE</strong></p> <p>I made some changes to my database handling and the error has changed slightly.</p> <pre><code>ERROR/Database(15235): Error inserting MY_MESSAGE ERROR/Database(15235): android.database.sqlite.SQLiteException: error code 5: database is locked ERROR/Database(15235): at android.database.sqlite.SQLiteStatement.native_execute(Native Method) ERROR/Database(15235): at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:61) ERROR/Database(15235): at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1591) ERROR/Database(15235): at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1435) ERROR/Database(15235): at mypackagename.DatabaseHelper.insertLogging(DatabaseHelper.java:190) ERROR/Database(15235): at mypackagename.ContentProvider.insert(ContentProvider.java:139) ERROR/Database(15235): at android.content.ContentProvider$Transport.insert(ContentProvider.java:198) ERROR/Database(15235): at android.content.ContentResolver.insert(ContentResolver.java:604) ERROR/Database(15235): at mypackagename.Activity$LogToDatabase.doInBackground(Activity.java:642) ERROR/Database(15235): at mypackagename.Activity$LogToDatabase.doInBackground(Activity.java:1) ERROR/Database(15235): at android.os.AsyncTask$2.call(AsyncTask.java:185) ERROR/Database(15235): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306) ERROR/Database(15235): at java.util.concurrent.FutureTask.run(FutureTask.java:138) ERROR/Database(15235): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) ERROR/Database(15235): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) ERROR/Database(15235): at java.lang.Thread.run(Thread.java:1019) </code></pre> <p>I didn't put much detail before in because I thought it was an issue with different processes or threads, but now I'm thinking the problem is more likely located in the code calling the database. </p> <p>Questions:</p> <p>1) Why am I hitting locks when I'm using a ContentProvider?<br> 2) Why does this not show up on an equivalent API 2.3.3 emulator?<br> 3) Does the fact that none of my code catches an exception mean that the error was handled properly and I can ignore it?<br> 4) I read in another place someone suggesting adjusting the busy timeout. How would I do that? </p> <p>The irony that it's my debug logging that's causing the error is not lost on me.</p> <p>If I can't solve it, my next step is to bundle the logging messages up in a list and dump them out in batches of ten at a time.</p> <p>Here's the path the through the code to the error:</p> <p>Activity:</p> <pre><code>private void logDatabaseMessage(String status, String message) { String[] args = {status, message}; LogToDatabase logTask = new LogToDatabase(); logTask.execute(args); } private class LogToDatabase extends AsyncTask&lt;String, Integer, Void&gt; { @Override protected Void doInBackground(final String... args) { try { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); String dateText = dateFormat.format(new Date()); ContentValues loggingValues = new ContentValues(); loggingValues.put(MyContentProvider.LOGGING_DATETIME, dateText); loggingValues.put(MyContentProvider.LOGGING_STATUS, args[0]); loggingValues.put(MyContentProvider.LOGGING_MESSAGE, args[1]); getContentResolver().insert(MyContentProvider.LOGGING_CONTENT_URI, loggingValues); } catch (Exception ex) { Log.e(TAG, "LogToDatabase.doInBackground threw exception: " + ex.getMessage()); ex.printStackTrace(); } return null; } } </code></pre> <p>ContentProvider:</p> <pre><code>@Override public Uri insert(Uri uri, ContentValues values) { Uri _uri = null; long rowID = 0; try { switch (uriMatcher.match(uri)) { case LOGGING: rowID = dbHelper.insertLogging(values); if (rowID == 0) throw new SQLException("Failed to insert row into " + uri); _uri = ContentUris.withAppendedId(LOGGING_CONTENT_URI, rowID); break; default: throw new SQLException("Failed to insert row into " + uri); } if (rowID != 0) getContext().getContentResolver().notifyChange(_uri, null); } catch (Exception ex) { Log.e(TAG, LogPrefix + "insert threw exception: " + ex.getMessage()); ex.printStackTrace(); } return _uri; } </code></pre> <p>DatabaseHelper:</p> <pre><code>public long insertLogging(ContentValues values) { long rowID = 0; try { rowID = db.insert(LOGGING_TABLE, null, values); } catch (Exception ex) { Log.e(TAG, LogPrefix + "ERROR: Failed to insert into logging table: " + ex.getMessage()); ex.printStackTrace(); } return rowID; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload