Home > Blockchain >  RoomDB crashes when migrating - Android
RoomDB crashes when migrating - Android

Time:10-18

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

  1. amending/creating the respective @Entity annotated class.

  2. including the class in the entities parameter of the @Database annotation

  3. compiling the project

  4. finding the class in the Java(Generated) that is the same name as the @Database annotated class but suffixed with _Impl

  5. finding the method within the class named createAllTables

  6. 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()
            )
  • Related