mardi 5 mai 2015

Android Lolipop: Delete then re-write existing database throws SQLiteReadOnlyDatabaseException on getWritableDatabase

This issue has been logged in official Android bug tracker for Lollipop:

http://ift.tt/1DEa0zz

as well as on Android developer preview, with a complete sample code and work around:

http://ift.tt/1KL2A39

yet there is no update till now. We tried the work around by Danny on the developer preview, but it wipes out data if app is killed/closed. Can someone help? Thanks in advance.

Reported by danny.b....@gmail.com, Aug 28, 2014 * Which version of the SDK are you using?

Building against 14, device is running L

  • Which Android build are you using? (e.g. LPV79)

LPV79

  • What device are you using?

Nexus 5

  • What steps will reproduce the problem? (Please provide the minimal reproducible test case.)

Background: We have a database that we maintain outside of the application that we keep in the /res/raw directory. On application start up we read the raw file and copy it to the appropriate database directory within our sandbox. When we need to make updates for to the database, we generate it again in a different project that reads in the SQL file and generates the appropriate database. We then pull the database off the device (simulator) and update our repo with the new database. We increase the version of this database each time we need to update it.

  1. Have a database file in your /res/raw directory, version set to 1 done as described above.

  2. Copy it over using an Input/Output stream. The copy happens within the SQLiteOpenHelper only if the file does not exist in our sandbox database directory. Do this before the call to openHelper.getWritableDatabase to get a handle on the actual database

  3. Increase the version of the database in your /res/raw directory and replace it. Also update the version number in the OpenHelper so that the onUpgrade is triggered.

  4. In the onUpgrade in your SQLiteOpenHelper, delete the old database using context.deleteDatabase and copy it over again as described in step 2 before the call to openHelper.getWritableDatabase.

  5. You will get a crash on the following line: SQLiteDatabase database = openHelper.getWritableDatabase();

    • How frequently does the issue occur? (e.g. 100% of the time, 10% of the time)

100% of the time when the onUpgrade is triggered in the OpenHelper

  • What is the expected output?

The device should not crash. This method has worked properly on 2.x, 3.x and 4.0-4.4 devices

  • What do you see instead?

The application crashes. As expected the previous version of the database is recovered from the journal file.

  • Relevant logcat output. 8-28 10:45:39.174 11725-11725/com.my.package.namespace A/MyDatabaseOpenHelper﹕ Remove old Database 08-28 10:45:39.191 11725-11725/com.my.package.namespace E/SQLiteLog﹕ (1032) statement aborts at 4: [PRAGMA user_version = 13] 08-28 10:45:39.192 11725-11725/com.my.package.namespace E/SQLiteLog﹕ (28) file unlinked while open: /data/data/com.my.package.namespace/databases/mycopied.db 08-28 10:45:39.194 11725-11725/com.my.package.namespace D/AndroidRuntime﹕ Shutting down VM 08-28 10:45:39.201 11725-11725/com.my.package.namespace E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: com.my.package.namespace, PID: 11725 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.my.package.namespace/com.my.package.namespace.SplashScreen}: android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 1032) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2255) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2317) at android.app.ActivityThread.access$800(ActivityThread.java:143) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1258) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5070) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:836) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:631) Caused by: android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 1032) at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method) at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:734) at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754) at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64) at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1676) at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1605) at android.database.sqlite.SQLiteDatabase.setVersion(SQLiteDatabase.java:873) at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:259) at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163) at com.my.package.namespace.MyDatabaseHelper.initializeDatabase(MyDatabaseHelper.java:---) at com.my.package.namespace.MyDatabaseHelper.(MyDatabaseHelper.java:---) at com.my.package.namespace.SplashScreen.copyMyDatabase(SplashScreen.java:---) at com.my.package.namespace.SplashScreen.onCreate(SplashScreen.java:---) at android.app.Activity.performCreate(Activity.java:5720) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1102) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2208) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2317) at android.app.ActivityThread.access$800(ActivityThread.java:143) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1258) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5070) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372)

Aucun commentaire:

Enregistrer un commentaire