Android SQLiteException: Failed to change locale for db to 'en_US'
Asked Answered
A

4

17

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
Aramanta answered 31/1, 2013 at 17:9 Comment(7)
I experience exactly the same problem and only on one of few devices. It doesn't depend on Locale set on the device, the exception is thrown whichever is set. Do you access the database from AsyncTask? And do you have two or more tables in one SQLiteDatabase object (which you possibly acces simultaneously)?Brodie
@anoniim I'm accessing the database from a Loader, so yeah it's done on another thread. This specific code should only be accessing one table, but there might be other threads accessing other tables at the same time. Do you think that's the issue?Aramanta
Please show the source for the CacheDbOpener?Kerianne
@Kerianne Here's the source for CacheDbOpenerAramanta
I guess, you are using a getContext() within the AsyncLoader, might be best to try use a static Context outside of the scope, i.e. declared at Application level or activity level, and use that when calling CacheDbOpener(static_Context) for example, and see what results you get?Kerianne
Do you open and close the database just before / after the request? I've just got the idea it could be caused by closing the database while there is another thread accessing it.Brodie
That could be it -- I switched my SQLiteOpenHelper over to using a singleton as per androiddesignpatterns.com/2012/05/… I was never able to replicate the error on my device (so it's hard to test), but so far I haven't seen this error again. Will update with this as the answer once more of my users have upgraded.Aramanta
R
4

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 lightening icon in the toolbar.

Ruffian answered 27/9, 2014 at 8:9 Comment(0)
D
2

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.

Divers answered 9/3, 2017 at 5:59 Comment(0)
N
1

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.

Nava answered 9/3, 2017 at 6:3 Comment(0)
D
0

Check if you have the same error on another phone. If the error doesn't appear there, it's probably that your phone cached something. Delete the database if possible and restart the phone.

It worked for me then.

Declinate answered 11/9, 2022 at 7:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.