I was trying to migrate existing room database to a newer version but got really weird error, which never happened to me before.
Application crashes when opened, instantly. In logcat, I get following error from room:
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([email protected]:29
at
android.database.sqlite. SQLiteOpenHelper. "getDatabaseLock
ed(SOLiteOpenHelperjava:515)
at
android.database.sqlite. [email protected]
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([email protected]:133)
at
androidx.room.RoomDatabase
As you can see, this message says that room expected 'this' but found 'this', but they are actually identical, there is no difference! O.o
And of course, here is my entity class:
@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
)
And my migration:
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
)
}
CodePudding user response:
expected 'this' but found 'this', but they are actually identical, there is no difference!
Not according to:-
expected ileSize=Columníname='fileSize', type='REAL', affinity='4 notNull=notNull,
found ileSize=Column(name=' fileSize', type='REAL', affinity='4 notNull=-notNull
In fact according to what you have posted, there are many discrepancies between expected and found, perhaps because you appear to have edited the log.
The most accurate CREATE TABLE SQL, that should always match what Room expects, can be ascertained by
amending/creating the respective
@Entity
annotated class.including the class in the
entities
parameter of the@Database
annotationcompiling the project
finding the class in the
Java(Generated)
that is the same name as the@Database
annotated class but suffixed with_Impl
finding the method within the class named
createAllTables
copying the respective SQL for the table.
- i.e. that SQL is the SQL that Room generates and would use (e.g. for a new install).
CodePudding user response:
Finally solved it by just writing:
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()
)