将第二个 Room 数据库添加到我的应用程序会导致异常:“Caused by: java.lang.IllegalStateException: Room cannot verify the data integrity”
Adding second Room database to my app causes exception: " Caused by: java.lang.IllegalStateException: Room cannot verify the data integrity"
我正在创建一个像素艺术编辑器应用程序,我已经有一个 Room 数据库来存储用户的创作,还有另一个我想添加的 Room 数据库,它将存储用户想要添加到应用程序的一些自定义调色板.
为此,我添加了以下数据库:
@Database(entities = [ColorPalette::class], version = 3)
abstract class ColorPalettesDatabase: RoomDatabase() {
abstract fun colorPalettesDao(): ColorPalettesDao
companion object {
private var instance: ColorPalettesDatabase? = null
fun getDatabase(context: Context): ColorPalettesDatabase {
if (instance == null) {
synchronized(ColorPalettesDatabase::class) {
if (instance == null) instance = Room.databaseBuilder(context.applicationContext, ColorPalettesDatabase::class.java, AppData.colorPalettesDBFileName).allowMainThreadQueries().build()
}
}
return instance!!
}
}
}
DAO:
@Dao
interface ColorPalettesDao {
@Insert
suspend fun insertColorPalette(colorPalette: ColorPalette)
@Query("SELECT * FROM ColorPalette ")
fun getAllColorPalettes(): LiveData<List<ColorPalette>>
@Query("DELETE FROM ColorPalette WHERE objId=:colorPaletteId")
fun deleteColorPalette(colorPaletteId: Int)
}
我在AppData
中添加了一个变量,并在MainActivity的onCreate
方法中进行了初始化:
class AppData {
companion object {
var pixelArtDBFileName = "pixel_art_db"
lateinit var pixelArtDB: PixelArtDatabase
var colorPalettesDBFileName = "color_palettes_db"
lateinit var colorPalettesDB: ColorPalettesDatabase
}
}
AppData.colorPalettesDB = ColorPalettesDatabase.getDatabase(this)
最后,我使用 ColorPalettesFragment.kt
文件中的数据库获取 ColorPalette
数据:
class ColorPalettesFragment(private val lifecycleOwner: LifecycleOwner) : Fragment(), ColorPalettesListener {
private var _binding: FragmentColorPalettesBinding? = null
private val binding get() = _binding!!
private lateinit var caller: ColorPalettesFragmentListener
private fun setUpRecyclerView() {
binding.apply {
fragmentColorPalettesRecyclerView.layoutManager = LinearLayoutManager(this@ColorPalettesFragment.activity).apply {
orientation = LinearLayoutManager.HORIZONTAL
}
AppData.colorPalettesDB.colorPalettesDao().getAllColorPalettes().observe(lifecycleOwner) {
fragmentColorPalettesRecyclerView.adapter = ColorPalettesAdapter(it, this@ColorPalettesFragment)
}
}
}
companion object {
fun newInstance(lifecycleOwner: LifecycleOwner) = ColorPalettesFragment(lifecycleOwner)
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is ColorPalettesFragmentListener) caller = context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentColorPalettesBinding.inflate(inflater, container, false)
setUpRecyclerView()
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onColorPaletteTapped(selectedColorPalette: ColorPalette) {
caller.onColorPaletteTapped(selectedColorPalette)
}
}
到目前为止,我在数据库为空时对其进行测试,我期望的是每当用户点击以下按钮时,他们都会看到空白 RecyclerView
:
不幸的是,当我 运行 应用程序并尝试导航到 Canvas 时,我什至无法进入屏幕,但出现以下异常:
2021-12-22 08:55:57.251 24474-24554/com.realtomjoney.pyxlmoose E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_1
Process: com.realtomjoney.pyxlmoose, PID: 24474
java.lang.RuntimeException: Exception while computing database live data.
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:92)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
Caused by: java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:154)
at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:135)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:201)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:427)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:151)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:112)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:706)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:483)
at androidx.room.RoomDatabase.query(RoomDatabase.java:526)
at androidx.room.util.DBUtil.query(DBUtil.java:86)
at com.realtomjoney.pyxlmoose.dao.ColorPalettesDao_Impl.call(ColorPalettesDao_Impl.java:108)
at com.realtomjoney.pyxlmoose.dao.ColorPalettesDao_Impl.call(ColorPalettesDao_Impl.java:105)
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:90)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
我已尝试查看其他解决方案以进行修复,但似乎无济于事。
这是来自 ColorPalettesDatabase
,因为当我在代码中删除它的所有用法时,异常就消失了。
如有任何帮助,我将不胜感激,以便我可以将调色板功能添加到我的应用程序中。
不幸的是,更新版本没有帮助,因此没有卸载应用程序。
有趣的评论:我想在未来悬赏这个但不幸的是我不能因为我在一个没有回复的问题上浪费了 150 声望哈哈
听起来您有一个现有版本的数据库并且更改了模式(即更改了 ColorPalette
class)。
Room 检测到此更改,因此建议您增加版本号。但是,您似乎没有任何迁移,因此更改版本号会失败。
IF 你没有数据(听起来像的情况到目前为止,我正在数据库为空时测试它,我期望的是每当用户点击以下按钮,他们将看到一个空白的 RecyclerView:)。编码 .fallbackToDestructiveMigration
可能会解决这个问题,因为在没有迁移的情况下,它将删除表然后创建表。
但是,以上没有回答,因此也没有卸载应用程序。。所以我猜你有一个持续的问题。
我建议先添加 .fallbackToDestructiveMigration
然后重新运行,如果失败则编辑你的问题以包含失败。
下一步,假设失败,尝试卸载并重新运行,然后,假设失败,在该场景下用失败编辑你的问题。
问题演示
ColorPalette class - 查看关于 运行s
的评论
@Entity
data class ColorPalette(
/* original V3 code */
@PrimaryKey
@ColumnInfo(name = "objId")
val objId: Long? = null,
val description: String,
val color: Long
/* additional code */
,
val extra: String
)
ColorPaletteDao(同栏无LiveData)
@Dao
interface ColorPalettesDao {
@Insert
fun insertColorPalette(colorPalette: ColorPalette)
@Query("SELECT * FROM ColorPalette ")
fun getAllColorPalettes(): /*LiveData<*/List<ColorPalette>/*>*/ /* for testing without LiveData */
@Query("DELETE FROM ColorPalette WHERE objId=:colorPaletteId")
fun deleteColorPalette(colorPaletteId: Int)
}
ColorPalleteDatabase(相同但稍后见)
MainActivity演示
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = ColorPalettesDatabase.getDatabase(this)
val dao = db.colorPalettesDao()
dao.getAllColorPalettes()
}
}
运行 1 - 只有 ColorPalette 的原始代码,即没有 extra列。
- 运行s 精细数据库创建(根据 AppInspection):-
运行 2 - 引入extra列,什么都不做,运行
- 哎呀!!!!
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so70444736kotlinroomincreaseversion/a.a.so70444736kotlinroomincreaseversion.MainActivity}: java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
运行 3 - 将版本号从 3 增加到 4 和 运行
- 哎呀!!!!
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so70444736kotlinroomincreaseversion/a.a.so70444736kotlinroomincreaseversion.MainActivity}: java.lang.IllegalStateException: A migration from 3 to 4 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
运行 4 添加 .fallbackToDestructiveMigration()
到 ColorPaletteDatabase 和 运行
- 运行s OK,数据库:-
将一切重置为初始状态(包括卸载应用程序)和运行 运行 1 和运行 2
- 与 运行 2 预期的相同问题。
卸载应用程序但没有任何更改(所以额外的列和版本 3)
- 运行很好,数据库有 extra 列
因此
为什么建议还有其他问题,因为两个建议的初始修复:-
- 随
.fallbackToDestructiveMigration
增加版本,
- 卸载应用程序并重新运行
两者都可以纠正所报告的问题。
我正在创建一个像素艺术编辑器应用程序,我已经有一个 Room 数据库来存储用户的创作,还有另一个我想添加的 Room 数据库,它将存储用户想要添加到应用程序的一些自定义调色板.
为此,我添加了以下数据库:
@Database(entities = [ColorPalette::class], version = 3)
abstract class ColorPalettesDatabase: RoomDatabase() {
abstract fun colorPalettesDao(): ColorPalettesDao
companion object {
private var instance: ColorPalettesDatabase? = null
fun getDatabase(context: Context): ColorPalettesDatabase {
if (instance == null) {
synchronized(ColorPalettesDatabase::class) {
if (instance == null) instance = Room.databaseBuilder(context.applicationContext, ColorPalettesDatabase::class.java, AppData.colorPalettesDBFileName).allowMainThreadQueries().build()
}
}
return instance!!
}
}
}
DAO:
@Dao
interface ColorPalettesDao {
@Insert
suspend fun insertColorPalette(colorPalette: ColorPalette)
@Query("SELECT * FROM ColorPalette ")
fun getAllColorPalettes(): LiveData<List<ColorPalette>>
@Query("DELETE FROM ColorPalette WHERE objId=:colorPaletteId")
fun deleteColorPalette(colorPaletteId: Int)
}
我在AppData
中添加了一个变量,并在MainActivity的onCreate
方法中进行了初始化:
class AppData {
companion object {
var pixelArtDBFileName = "pixel_art_db"
lateinit var pixelArtDB: PixelArtDatabase
var colorPalettesDBFileName = "color_palettes_db"
lateinit var colorPalettesDB: ColorPalettesDatabase
}
}
AppData.colorPalettesDB = ColorPalettesDatabase.getDatabase(this)
最后,我使用 ColorPalettesFragment.kt
文件中的数据库获取 ColorPalette
数据:
class ColorPalettesFragment(private val lifecycleOwner: LifecycleOwner) : Fragment(), ColorPalettesListener {
private var _binding: FragmentColorPalettesBinding? = null
private val binding get() = _binding!!
private lateinit var caller: ColorPalettesFragmentListener
private fun setUpRecyclerView() {
binding.apply {
fragmentColorPalettesRecyclerView.layoutManager = LinearLayoutManager(this@ColorPalettesFragment.activity).apply {
orientation = LinearLayoutManager.HORIZONTAL
}
AppData.colorPalettesDB.colorPalettesDao().getAllColorPalettes().observe(lifecycleOwner) {
fragmentColorPalettesRecyclerView.adapter = ColorPalettesAdapter(it, this@ColorPalettesFragment)
}
}
}
companion object {
fun newInstance(lifecycleOwner: LifecycleOwner) = ColorPalettesFragment(lifecycleOwner)
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is ColorPalettesFragmentListener) caller = context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentColorPalettesBinding.inflate(inflater, container, false)
setUpRecyclerView()
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onColorPaletteTapped(selectedColorPalette: ColorPalette) {
caller.onColorPaletteTapped(selectedColorPalette)
}
}
到目前为止,我在数据库为空时对其进行测试,我期望的是每当用户点击以下按钮时,他们都会看到空白 RecyclerView
:
不幸的是,当我 运行 应用程序并尝试导航到 Canvas 时,我什至无法进入屏幕,但出现以下异常:
2021-12-22 08:55:57.251 24474-24554/com.realtomjoney.pyxlmoose E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_1
Process: com.realtomjoney.pyxlmoose, PID: 24474
java.lang.RuntimeException: Exception while computing database live data.
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:92)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
Caused by: java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:154)
at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:135)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:201)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:427)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:151)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:112)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:706)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:483)
at androidx.room.RoomDatabase.query(RoomDatabase.java:526)
at androidx.room.util.DBUtil.query(DBUtil.java:86)
at com.realtomjoney.pyxlmoose.dao.ColorPalettesDao_Impl.call(ColorPalettesDao_Impl.java:108)
at com.realtomjoney.pyxlmoose.dao.ColorPalettesDao_Impl.call(ColorPalettesDao_Impl.java:105)
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:90)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
我已尝试查看其他解决方案以进行修复,但似乎无济于事。
这是来自 ColorPalettesDatabase
,因为当我在代码中删除它的所有用法时,异常就消失了。
如有任何帮助,我将不胜感激,以便我可以将调色板功能添加到我的应用程序中。
不幸的是,更新版本没有帮助,因此没有卸载应用程序。
有趣的评论:我想在未来悬赏这个但不幸的是我不能因为我在一个没有回复的问题上浪费了 150 声望哈哈
听起来您有一个现有版本的数据库并且更改了模式(即更改了 ColorPalette
class)。
Room 检测到此更改,因此建议您增加版本号。但是,您似乎没有任何迁移,因此更改版本号会失败。
IF 你没有数据(听起来像的情况到目前为止,我正在数据库为空时测试它,我期望的是每当用户点击以下按钮,他们将看到一个空白的 RecyclerView:)。编码 .fallbackToDestructiveMigration
可能会解决这个问题,因为在没有迁移的情况下,它将删除表然后创建表。
但是,以上没有回答,因此也没有卸载应用程序。。所以我猜你有一个持续的问题。
我建议先添加 .fallbackToDestructiveMigration
然后重新运行,如果失败则编辑你的问题以包含失败。
下一步,假设失败,尝试卸载并重新运行,然后,假设失败,在该场景下用失败编辑你的问题。
问题演示
ColorPalette class - 查看关于 运行s
的评论@Entity
data class ColorPalette(
/* original V3 code */
@PrimaryKey
@ColumnInfo(name = "objId")
val objId: Long? = null,
val description: String,
val color: Long
/* additional code */
,
val extra: String
)
ColorPaletteDao(同栏无LiveData)
@Dao
interface ColorPalettesDao {
@Insert
fun insertColorPalette(colorPalette: ColorPalette)
@Query("SELECT * FROM ColorPalette ")
fun getAllColorPalettes(): /*LiveData<*/List<ColorPalette>/*>*/ /* for testing without LiveData */
@Query("DELETE FROM ColorPalette WHERE objId=:colorPaletteId")
fun deleteColorPalette(colorPaletteId: Int)
}
ColorPalleteDatabase(相同但稍后见)
MainActivity演示
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = ColorPalettesDatabase.getDatabase(this)
val dao = db.colorPalettesDao()
dao.getAllColorPalettes()
}
}
运行 1 - 只有 ColorPalette 的原始代码,即没有 extra列。
- 运行s 精细数据库创建(根据 AppInspection):-
运行 2 - 引入extra列,什么都不做,运行
- 哎呀!!!!
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so70444736kotlinroomincreaseversion/a.a.so70444736kotlinroomincreaseversion.MainActivity}: java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
运行 3 - 将版本号从 3 增加到 4 和 运行
- 哎呀!!!!
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so70444736kotlinroomincreaseversion/a.a.so70444736kotlinroomincreaseversion.MainActivity}: java.lang.IllegalStateException: A migration from 3 to 4 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
运行 4 添加 .fallbackToDestructiveMigration()
到 ColorPaletteDatabase 和 运行
- 运行s OK,数据库:-
将一切重置为初始状态(包括卸载应用程序)和运行 运行 1 和运行 2
- 与 运行 2 预期的相同问题。
卸载应用程序但没有任何更改(所以额外的列和版本 3)
- 运行很好,数据库有 extra 列
因此
为什么建议还有其他问题,因为两个建议的初始修复:-
- 随
.fallbackToDestructiveMigration
增加版本, - 卸载应用程序并重新运行
两者都可以纠正所报告的问题。