Tengo una migración compleja agregada a mi generador de base de datos Room. Como esta migración en particular requiere descargar algunos datos de un servidor, estoy usando una pantalla de inicio para esperar a que termine todo el proceso antes de abrir la actividad principal de la aplicación.
El problema es que las migraciones no se ejecutan automáticamente en el método "build()", ya que parecen ejecutarse internamente en un subproceso separado.
También pensé en usar RoomDatabase.Callback para detectar cuándo se abre la base de datos, pero como la migración es compleja e intenta descargar datos de un servidor, puede fallar y la aplicación puede quedarse esperando para siempre.
Necesito activar la migración y esperar a que se complete y, si es posible, detectar errores de migración.
Este es el código en la clase de aplicación:
appLoadingStatus.value = AppLoadingStatus.INITIALIZING db= Room.databaseBuilder(this@App,Database::class.java,"app-database") .addMigrations(Database.MIGRATION_12_13).build() //Here I need to wait for migrations to finish in case they are executed, and catch ay possible errors appLoadingStatus.value = AppLoadingStatus.INITIALIZEDY esta es la migración:
val MIGRATION_12_13: Migration = object : Migration(12, 13) { override fun migrate(database: SupportSQLiteDatabase) { runBlocking(Dispatchers.Main) { val newIds =App.instance.getIdsForMigration()?:throw IllegalStateException("Unable do get data from server") database.execSQL("ALTER TABLE Coin ADD `id` INTEGER NOT NULL") newIds.forEach {symbolIdPair-> database.execSQL("UPDATE Coin SET id='${symbolIdPair.id}' where symbol='${symbolIdPair.symbol}'") } database.execSQL("ALTER TABLE Coin RENAME TO `Coin_backup`") database.execSQL("CREATE TABLE `Coin` (`symbol` TEXT NOT NULL, `id` INTEGER NOT NULL, `name` TEXT, `imageSrc` TEXT, `rank` INTEGER NOT NULL, `max_supply` REAL NOT NULL, `quantity` REAL NOT NULL, `market` TEXT NOT NULL, `type` TEXT, `price` REAL NOT NULL, `lastUpdate` INTEGER NOT NULL, `lastVolume` REAL NOT NULL, `lastVolumeTo` REAL NOT NULL, `volumeDay` REAL NOT NULL, `volumeDayTo` REAL NOT NULL, `volume24h` REAL NOT NULL, `volume24hTo` REAL NOT NULL, `openDay` REAL NOT NULL, `highDay` REAL NOT NULL, `lowDay` REAL NOT NULL, `open24h` REAL NOT NULL, `high24h` REAL NOT NULL, `low24h` REAL NOT NULL, `change24h` REAL NOT NULL, `changePct24h` REAL NOT NULL, `changeDay` REAL NOT NULL, `changePctDay` REAL NOT NULL, `supply` REAL NOT NULL, `mktCap` REAL NOT NULL, `totalVolume24h` REAL NOT NULL, `totalVolume24hTo` REAL NOT NULL, `favourite` INTEGER NOT NULL, PRIMARY KEY(`id`))") database.execSQL("INSERT INTO `Coin` SELECT * FROM `Coin_backup`") } } }Bueno, después de probar mucho y leer la mitad del código fuente de Room, resulta que las migraciones se ejecutarán la primera vez que acceda a la base de datos construida. Además, cualquier error ocurrido durante la migración se mostrará en esta primera llamada.
Es importante que, si utiliza corrutinas, tenga cuidado al llamar a cualquier método relacionado con la base de datos en los bloques runBlocking, ya que puede provocar un punto muerto en la implementación de la sala.
Simplemente puede llamar
db.openHelper.readableDatabaseY esperar a que se complete. Los errores también se pueden detectar aquí, por lo que puede detectar dónde falla la migración.
No sabes hasta que sabes...