I recently updated one of my (open-source) Android apps and my users are getting an exception that I can't replicate. The key parts are :
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
and then
Caused by: android.database.sqlite.SQLiteException: Failed to change locale for db '/data/data/com.airlocksoftware.hackernews/databases/hacker_news_cache.db' to 'en_US'.
This is happening on devices with Android 2.3 - 4.2.1, and in multiple places within the app where I try to connect to a database. I am closing the database after I use it.
I can't find much information about the "failed to change locale for db" exception. When I look at the source for SQLiteConnection (line 386) it seems to be a problem with either the 'android_metadata' table or 'updating the indexes using a new locale'.
Here is the code that's causing the exception (on Github).
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:137)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
at java.util.concurrent.FutureTask.run(FutureTask.java:239)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:856) Caused by: android.database.sqlite.SQLiteException: Failed to change locale for db '/data/data/com.airlocksoftware.hackernews/databases/hacker_news_cache.db' to 'en_US'.
at android.database.sqlite.SQLiteConnection.setLocaleFromConfiguration(SQLiteConnection.java:386)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:218)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:854)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:229)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
at com.airlocksoftware.database.DbInterface.(DbInterface.java:28)
at com.airlocksoftware.hackernews.loader.StoryLoader.loadStories(StoryLoader.java:62)
at com.airlocksoftware.hackernews.loader.StoryLoader.loadInBackground(StoryLoader.java:54)
at com.airlocksoftware.hackernews.loader.StoryLoader.loadInBackground(StoryLoader.java:1)
at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40)
at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
... 3 more Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:548)
at android.database.sqlite.SQLiteConnection.setLocaleFromConfiguration(SQLiteConnection.java:364)
... 24 more
check your database content, specially 'android_metadata'. it's a table with this DDL:
CREATE TABLE android_metadata (
locale TEXT
);
which should contain at least one record with this content:
en_US
this solved my own problem.
for more details:
open your database file with a sqlite editor such as SQLiteStudio then open android_metadata table (if it does not exist create it. (you may create it with the query editor (tools>open query editor) and copy/paste the DDL code above)
for inserting the record you may copy/paste this line in the query editor:
insert into android_metadata values ('en_us');
hint: to run the query in SQLiteStudio you should push the button with icon in the toolbar.
The key is android.database.sqlite.SQLiteDatabaseLockedException
.
I had the same issue, and it kept increasing with the increase in Database Locking.
What to do? - Eliminate Database locking.
How? - Make sure no concurrent write calls take place, and
You may read more about avoiding database locking here and in this very well explained SO answer.
I would suggest shifting all your write calls on a single thread, this way avoiding locking. You could use AsyncQueryHandler for this.
If you're changing your locale in the app, make sure you change it before you open your database.
I was having this same issue in my app when I was switching the locale after opening my database, and it was trying to switch to a different database based on the locale, which didn't exist.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With