拦截房间迁移错误以重新创建数据库
Intercepting room migration errors to recreate the DB
https://medium.com/google-developers/understanding-migrations-with-room-f01e04b07929
上有一篇关于房间迁移的很棒的文章
但是,我仍然想念 Room 中的 "disaster" 恢复机制(例如 fallbackToDestructiveRecreationOnMigrationError(),当发生奇怪的事情时会清除并重新创建数据库)
这是发生在我们身上的事情:
开发人员通过迁移推送了版本 9,但模式 9.json 不符合(我不知道这怎么可能)=> room 进行了迁移并且没有错误。
然后,当我们提供版本 10 时,文件 9.json 已更改 => 房间崩溃,用户无法再访问该应用程序(这是正常现象)。
我们不得不告诉我们的用户擦除他们的数据(这不是技术问题,因为我们在应用程序启动时重新同步数据库,但这是一个 public 关系问题)
我认为在构建器中使用 openHelperFactory 应该是可能的,但这对我来说还远远不够深入房间内部:(
经过多次尝试和绝望,这是我使用的解决方案:
abstract class MainDatabase: RoomDatabase() {
companion object {
val instance: MainDatabase by lazy {
if (_instance == null) throw IllegalStateException("someone should have called init fun")
_instance!!
}
private var _instance: MainDatabase? = null
fun init(mainApplication: MainApplication) {
_instance = init_(mainApplication)
//force db opening and if it fails, we try to destroy and recreate the db
try {
_instance!!.openHelper.writableDatabase
} catch (e: Exception) {
Log.e("Database", "there was an error during DB opening => trying to destroy and recreate", e)
_instance!!.openHelper.close()
val dbPath = mainApplication.getDatabasePath(DB_NAME)
if (SQLiteDatabase.deleteDatabase(dbPath)) {
_instance = init_(mainApplication)
_instance!!.openHelper.writableDatabase
}
}
}
private fun init_(mainApplication: MainApplication): MainDatabase {
return Room.databaseBuilder(mainApplication, MainDatabase::class.java, DB_NAME)
.addMigrations(MIGRATION_1, MIGRATION_2, MIGRATION_3, MIGRATION_4, MIGRATION_5, MIGRATION_6, MIGRATION_7, MIGRATION_8, MIGRATION_9, MIGRATION_10)
.build()
}
}
这个解决方案的真正缺点是第一次访问数据库是在主线程上完成的...
如果谁有更好的解决方案,请分享!
https://medium.com/google-developers/understanding-migrations-with-room-f01e04b07929
上有一篇关于房间迁移的很棒的文章但是,我仍然想念 Room 中的 "disaster" 恢复机制(例如 fallbackToDestructiveRecreationOnMigrationError(),当发生奇怪的事情时会清除并重新创建数据库)
这是发生在我们身上的事情:
开发人员通过迁移推送了版本 9,但模式 9.json 不符合(我不知道这怎么可能)=> room 进行了迁移并且没有错误。
然后,当我们提供版本 10 时,文件 9.json 已更改 => 房间崩溃,用户无法再访问该应用程序(这是正常现象)。
我们不得不告诉我们的用户擦除他们的数据(这不是技术问题,因为我们在应用程序启动时重新同步数据库,但这是一个 public 关系问题)
我认为在构建器中使用 openHelperFactory 应该是可能的,但这对我来说还远远不够深入房间内部:(
经过多次尝试和绝望,这是我使用的解决方案:
abstract class MainDatabase: RoomDatabase() {
companion object {
val instance: MainDatabase by lazy {
if (_instance == null) throw IllegalStateException("someone should have called init fun")
_instance!!
}
private var _instance: MainDatabase? = null
fun init(mainApplication: MainApplication) {
_instance = init_(mainApplication)
//force db opening and if it fails, we try to destroy and recreate the db
try {
_instance!!.openHelper.writableDatabase
} catch (e: Exception) {
Log.e("Database", "there was an error during DB opening => trying to destroy and recreate", e)
_instance!!.openHelper.close()
val dbPath = mainApplication.getDatabasePath(DB_NAME)
if (SQLiteDatabase.deleteDatabase(dbPath)) {
_instance = init_(mainApplication)
_instance!!.openHelper.writableDatabase
}
}
}
private fun init_(mainApplication: MainApplication): MainDatabase {
return Room.databaseBuilder(mainApplication, MainDatabase::class.java, DB_NAME)
.addMigrations(MIGRATION_1, MIGRATION_2, MIGRATION_3, MIGRATION_4, MIGRATION_5, MIGRATION_6, MIGRATION_7, MIGRATION_8, MIGRATION_9, MIGRATION_10)
.build()
}
}
这个解决方案的真正缺点是第一次访问数据库是在主线程上完成的...
如果谁有更好的解决方案,请分享!