我试图将现有的房间数据库迁移到一个新版本,但遇到了一个非常奇怪的错误,以前从未发生过。
应用程序在打开时立即崩溃。在logcat中,我从房间中得到以下错误:
java.lang.RuntimeException: Exception while computing
database live data.
at
androidx.room.Room TrackingLiveData.refreshRunnableSlamb
da-0(RoomTrackingLiveData.kt:74)
at androidx.room.RoomTrackingLiveData.
$r8slambdaSUkyPj-RMUOTXOMbUuy5NWSwMoOE(Unknown
Source:0)
at androidx.room. RoomTrackingLiveData$
șExternalSyntheticLambdaO.run(Unknown Source:2)
at
java.util.concurrent.Thre adPoolExecutor.runWorker(ThreadPo
olExecutor.java:1137)
at
java.util.concurrent.ThreadPoolExecutor$ Worker.run(ThreadP
oolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Caused by: java.lang.llegalStateException: Migration didn't
properly handle: downloads(ge.mov.mobile.data.local.entity.O
fineMovieEntity).
Expected;
Tablelnto(name='downloads'
columns-(src=Columníname='src', type='TEXT, affinity=`2",
notNull=notNull, primarykeyPosition=0, defaultValue='null").
filePath=Columníname='filePath', type="TEXT
affinity="2', notNull=notNull, primarykeyPosition=0,
defaultValue='null'), i=-Column(name='i', type='INTEGER
affinity='3', notNull-notNull primarykeyPosition=1,
JefaultValue='null'), episode=Column(name='episode
type='INTEGER, affinity='3", notNull=notNull,
primarykeyPosition=0, defaultValue='null"),
language=Columníname='language', type='TEXT"
affinity="2", notNull-notNull primarykeyPosition=C
defaultValue='nul'), adjarald=Columníname='adjarald'
type='INTEGER, affinity='3", notNull=notNul,
primarykeyPosition=0, defaultValue-'null'),
titleEng=Column(name='titleEng', type='TEXT', affinity='2",
notNull=notNul, primarykeyPosition=0, defaultValue='null").
quality=Columníname='quality', type='TEXT, affinity="2"
notNull=notNull, primarykeyPosition=0, defaultValue='null'),
titleGeo=Column(name='titleGeo', type='TEXT', affinity='2"
notNull=notNull, primarykeyPosition=0, defaultValue='null'),
ileSize=Columníname='fileSize', type='REAL', affinity='4
notNull=notNull, primarykeyPosition=0, defaultValue='null"),
season=Column(name='season', type='INTEGER', affinity=*3",
notNull=notNull, primarykeyPosition=0, defaultValue='null"),
savedAt=Columníname='savedAt, type='INTEGER',
affinity='3', notNull=notNul, primarykeyPosition=0,
defaultvalue='null"), id=Column(name='id', type='INTEGER"
affinity='3', notNull=notNul, primarykeyPosition=0,
defaultValue=`nul"), poster-Columni(name=' poster'
type="BLOB', affinity='5', notNull=notNull,
primaryKeyPosition=0, defaultValue='null')), foreignKeys=[],
indices-[
Found:
Tablelnfo(name='downloads'
columns=(src=Column(name='src', type='TEXT, affinity="2"
notNull=notNull, primarykeyPosition=0, defaultValue='null'),
ilePath=Column(name =*filePath', type="TEXT'
affinity='2", notNull=notNull, primarykeyPosition=0,
defaultValue='null'), i=Columníname='i', type='INTEGER'
afhnity='3', notNull-notNul, primarykeyPosition=1,
lefaultValue='null'), episode=Columniname='episode
type='INTEGER', affinity='3", notNull=-notNull,
primarykeyPosition=0, defaultValue='null"),
language=Columníname='language', type=TEXT"
affinity="2', notNull-=notNull, primarykeyPosition=0,
defaultValue='nul'), adjarald=Column(name='adjarald"
type='INTEGER', affinity='3', notNull-notNull,
primarykeyPosition=0, defaultValue='null'),
titleEng=Column(name ='titleEng', type='TEXT, affinity='2"
notNull=notNul, primarykeyPosition=0, defaultValue='null"),
quality=Columníname='quality', ype ='TEXT, affinity=`2"
notNull=notNull, primarykeyPosition=0, defaultValue='null'),
titleGeo=Column(name='titleGeo', type='TEXT', affinity='2"
notNull=notNull, primarykeyPosition=0, defaultValue='null'),
ileSize=Column(name=' fileSize', type='REAL', affinity='4
notNull=-notNull, primarykeyPosition=0, defaultValue='nu').
season=Column(name='season', type='INTEGER affinity=" P
notNull=notNul, primarykeyPosition=0, defaultValue=" nul').
savedAt=Column(name='savedAt, type='INTEGER
affinity='3', notNull=notNul, primarykeyPosition=0,
defaultValue='null"), id=Column(name='id', type='INTEGER",
affinity= 3', notNull=notNull, primarykeyPosition=0
defaultValue='null'), poster=Column(name='poster',
type="BLOB', affnity='5', notNull-notNull,
primarykeyPosition=0, defaultvalue='nul'), foreignkeys=[].
indices-[
at
androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelp
er.kt:94)
at
androidx.sqIlite.db.framework.FrameworkS@LiteOpenHelper$
OpenHelper.onUpgrade(FrameworkS@LiteOpenHelper.java:29
at
android.database.sqlite. SQLiteOpenHelper. "getDatabaseLock
ed(SOLiteOpenHelperjava:515)
at
android.database.sqlite. S@LiteOpenHelper.getWritableDatab
ase(S@LiteOpenHelper,java:413)
at
androidx.sqlite.db.framework.FrameworkS@LiteOpenHelper$
OpenHelper.getwritableOrReadableDatabase(FrameworkSOL
iteOpenHelperjava:273)
androidx.sqlite.db.framework.FrameworkSQLiteOpenHelpers
OpenHelper.innerGetDatabase(FrameworkS@LiteOpenHelper.
java:225)
at
androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$
OpenHelper.getSupportDatabase(FrameworkSQLiteOpenHel
perjava:183)
ndroidx.sqlite.db.framework.FrameworkS@LiteOpenHelper.,g
etWrit ableDatabase(FrameworkS@LiteOpenHelper.java:133)
at
androidx.room.RoomDatabase
正如你所看到的,这条消息说房间期望"这个",但发现"这个"。但它们实际上是相同的,没有区别!O.O
当然,这是我的实体类:
@Entity(tableName = "downloads")
data class OfflineMovieEntity(
@PrimaryKey(autoGenerate = true)
val i: Int,
var id: Long,
var adjaraId: Long,
var titleGeo: String,
var titleEng: String,
var poster: Bitmap,
var season: Int,
var episode: Int,
var language: String,
var quality: String,
var src: String,
var filePath: String,
var fileSize: Double,
var savedAt: Long
)
我的迁移:
object Migrations {
private const val TYPE_INT = "INTEGER"
private const val TYPE_STRING = "TEXT"
private const val TYPE_DOUBLE = "REAL"
private const val TYPE_BITMAP = "BLOB"
private const val TYPE_LONG = "INTEGER"
private const val TYPE_BOOLEAN = "INTEGER"
private fun SupportSQLiteDatabase.createTable(
tableName: String, values: HashMap<String, String>
) {
var sql = "CREATE TABLE IF NOT EXISTS '$tableName' ("
values.entries.forEach {
sql += "'${it.key}' ${it.value.uppercase()}"
sql += if (it == values.entries.last()) "" else ", "
}
sql += ");"
execSQL(sql)
}
private val MIGRATION_17_18 = object : Migration(17, 18) {
override fun migrate(database: SupportSQLiteDatabase) {
database.createTable(
"downloads", hashMapOf(
OfflineMovieEntity::i.name to "$TYPE_LONG PRIMARY KEY",
OfflineMovieEntity::id.name to "$TYPE_LONG NOT NULL",
OfflineMovieEntity::adjaraId.name to "$TYPE_LONG NOT NULL",
OfflineMovieEntity::titleEng.name to "$TYPE_STRING NOT NULL",
OfflineMovieEntity::titleGeo.name to "$TYPE_STRING NOT NULL",
OfflineMovieEntity::poster.name to "$TYPE_BITMAP NOT NULL",
OfflineMovieEntity::season.name to "$TYPE_INT NOT NULL",
OfflineMovieEntity::episode.name to "$TYPE_INT NOT NULL",
OfflineMovieEntity::language.name to "$TYPE_STRING NOT NULL",
OfflineMovieEntity::quality.name to "$TYPE_STRING NOT NULL",
OfflineMovieEntity::src.name to "$TYPE_STRING NOT NULL",
OfflineMovieEntity::filePath.name to "$TYPE_STRING NOT NULL",
OfflineMovieEntity::fileSize.name to "$TYPE_DOUBLE NOT NULL",
OfflineMovieEntity::savedAt.name to "$TYPE_LONG NOT NULL",
)
)
}
}
val migrations = arrayOf(
MIGRATION_1_2,
MIGRATION_2_3,
MIGRATION_3_4,
MIGRATION_4_5,
MIGRATION_5_6,
MIGRATION_9_10,
MIGRATION_10_11,
MIGRATION_11_12,
MIGRATION_12_13,
MIGRATION_13_14,
MIGRATION_14_15,
MIGRATION_15_16,
MIGRATION_16_17,
MIGRATION_17_18
)
}
预期为'this',但实际为'this',没有区别!
不符合:-
预期ileSize=Columníname='fileSize', type='REAL', affinity='4 notNull=notNull,
找到ileSize=Column(name=' fileSize', type='REAL', affinity='4 notNull=-notNull
事实上,根据你发布的内容,预期和发现之间有很多差异,可能是因为你似乎编辑了日志。
可以确定最准确的CREATE TABLE SQL,它应该始终与Room期望的相匹配
-
修改/创建相应的
@Entity
注释类。 -
包括
@Database
注释的entities
参数中的类 -
编制项目
-
在
Java(Generated)
中查找与@Database
注释类同名但后缀为_Impl
的类 -
在名为
createAllTables
的类中查找方法 -
复制表的相应SQL。
- 即SQL是Room生成并将使用的SQL(例如,用于新安装(
只需编写即可最终解决问题
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS downloads (
'i' INTEGER NOT NULL PRIMARY KEY,
'id' INTEGER,
'adjaraId' INTEGER,
'titleEng' TEXT,
'titleGeo' TEXT,
'poster' BLOB DEFAULT NULL,
'season' INTEGER,
'episode' INTEGER,
'language' TEXT,
'quality' TEXT,
'src' TEXT,
'filePath' TEXT,
'fileSize' REAL,
'savedAt' INTEGER
);
""".trimIndent()
)