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.
This doesn't entirely answer the question, but you may also want to check out this article, and see if perhaps you can work this into your DbHelperSingleton
, since it seems to be the same error you are facing:
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.
来源:https://stackoverflow.com/questions/14631316/android-sqliteexception-failed-to-change-locale-for-db-to-en-us