If there is an error during the onUpgrade method of my extended SQLiteOpenHelper class, the app crashes. I'd instead prefer to let the app continue opening the database and disable certain features that depend on the new schema.
I achieved it as follows, but feel this is a bit convoluted. Does anyone know a more supported or better way to let my app continue running on a failed database upgrade?
DBHelper class:
class DBHelper extends SQLiteOpenHelper {
public int _actual_version = 0;
public DBHelper(Context context) {
super(context, "example_db_name", null, 2);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
this._actual_version = oldVersion;
try {
//do some upgrade code
this._actual_version = newVersion;
} catch (Throwable t) {
//end the current transaction without committing
db.endTransaction();
//begin a new transaction to let the app continue
//this also increments the db version
db.beginTransaction();
}
}
public int getActualVersion() { return this._actual_version; }
}
In my DB Adapter class:
class DBAdapter {
private final DBHelper dbHelper;
SQLiteDatabase dbW;
public DBAdapter(Context context) {
dbHelper = new DBHelper(context);
dbW = dbHelper.getWritableDatabase();
if (dbHelper.getActualVersion() != 2) {
dbW.beginTransaction();
dbW.setVersion(dbHelper.getActualVersion());
dbW.setTransactionSuccessful();
dbW.endTransaction();
}
}
}
Here is a stack trace of the app crash. I am simulating an error by using CREATE TBLE
instead of CREATE TABLE
in the query.
2021-09-13 09:00:00 7931-7931/com.example.android.myapp E/SQLiteLog: (1) near "TBLE": syntax error in "CREATE TBLE setting (id INTEGER PRIMARY KEY, setting TEXT NOT NULL)"
2021-09-13 09:00:00 7931-7931/com.example.android.myapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.myapp, PID: 7931
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.myapp/com.example.android.myapp.MainActivity}: android.database.sqlite.SQLiteException: near "TBLE": syntax error (code 1 SQLITE_ERROR): , while compiling: CREATE TBLE setting (id INTEGER PRIMARY KEY, setting TEXT NOT NULL)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: android.database.sqlite.SQLiteException: near "TBLE": syntax error (code 1 SQLITE_ERROR): , while compiling: CREATE TBLE setting (id INTEGER PRIMARY KEY, setting TEXT NOT NULL)
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1045)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:652)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:590)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:61)
at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:33)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1919)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1841)
at com.example.android.myapp.DBHelper.onUpgrade(DBHelper.java:159)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:416)
at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:340)
at com.example.android.myapp.DBAdapter.<init>(DBAdapter.java:49)
at com.example.android.myapp.MainActivity.onCreate(MainActivity.java:59)
at android.app.Activity.performCreate(Activity.java:7994)
at android.app.Activity.performCreate(Activity.java:7978)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)