Estoy usando Android Room en una aplicación. Tengo una base de datos preconstruida en activos que necesito usar. Cada vez que actualizo la versión, necesito reemplazar la base de datos anterior con la base de datos nueva. Para ello he copiado la base de datos con el archivo convencional IO.
private fun copyDatabaseFile(context: Context) { val dbPath = context.getDatabasePath(DB_NAME) if (dbPath.exists() && AppPrefs.getInstance().dataBaseVersion== DATABASE_VERSION) { return } if(dbPath.delete())Log.e("datacopy", "file deleted") dbPath.parentFile.mkdirs() try { val inputStream = context.assets.open("databases/no_database.db") val output = FileOutputStream(dbPath) val buffer = ByteArray(8192) var length =0 while ({length = inputStream.read(buffer, 0, 8192); length}() > 0) { Log.e("datacopy", "Write") output.write(buffer, 0, length) } output.flush() output.close() inputStream.close() AppPrefs.getInstance().dataBaseVersion= DATABASE_VERSION } catch (e: IOException) { e.printStackTrace() } } }Aquí está el getter para la instancia de la base de datos: -
internal fun getDatabase(context: Context): MyDatabase? { if (INSTANCE == null) { synchronized(MyDatabase::class.java) { if (INSTANCE == null) { copyDatabaseFile(context) INSTANCE = Room.databaseBuilder( context.applicationContext, MyDatabase::class.java, DB_NAME) .addMigrations(MyDatabase.MIGRATION_1_2) .build() } } } return INSTANCE }La migración está vacía por ahora porque necesito borrar la anterior y copiar la nueva. Así que creo que la migración no es necesaria para esto.
@JvmField val MIGRATION_1_2: Migration = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { } }Primera vez todo funcionando bien. Cuando actualizo la versión de la base de datos, elimino el archivo antiguo, copio el archivo nuevo, pero Room devuelve los datos antiguos. No estoy seguro de cuál es el problema.
Incluso probé una respuesta anterior que sugiere:
¿Cómo usar la biblioteca de persistencia de salas con una base de datos precargada? biblioteca-con-base-de-datos-prellenada
También probé algunas otras cosas de Git, pero nada funcionó. ¿Cual podría ser el problema? Mi necesidad es reemplazar la base de datos anterior por una nueva cada vez que se actualice la versión de la base de datos.
El método más seguro y completo:
Diviértete closeRemoveCopy().
private fun closeRemoveCopy(outputFile: File){ // 1st: Close DB RoomHelper.getDatabase(applicationContext)?.close() // 2nd: Delete DB file outputFile.delete() // 3rd: Copy New DB file copyDatabase(this) // 4th: TO OPEN DB val handler = Handler(Looper.getMainLooper()) handler.postDelayed({ helper = Room.databaseBuilder(this@MainActivity, RoomHelper::class.java, "room_database.db") .build() }, 0) // 5th: Reopen App. If you don't reopen the app, it will be closed. val mainActivity = Intent(applicationContext,MainActivity::class.java) // NOW RESTARTING ACTIVITY SO DATABASE IS REFRESHED mainActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) startActivity(mainActivity) }Y diviértete con copyDatabase().
private fun copyDatabase(context: Context) { val dbPath: File = context.getDatabasePath("room_database.db") // If the database already exists, return if (dbPath.exists()) { Log.d("Show Result", "db Path Exists. $dbPath") return } dbPath.parentFile?.mkdirs() // Try to copy DB file try { val inputStream: InputStream = context.assets.open("databases/room_database.db") val output: OutputStream = FileOutputStream(dbPath) val buffer = ByteArray(8192) var length: Int while (inputStream.read(buffer, 0, 8192).also { length = it } > 0) { output.write(buffer, 0, length) } output.flush() output.close() inputStream.close() } catch (e: IOException) { Log.d("Show Result", "Failed", e) e.printStackTrace() } }Y use.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // management db file version val preferences = getSharedPreferences("prefGetData", MODE_PRIVATE) val editor = preferences.edit() val getCheckData = preferences?.getString("getData", "") val currentDbFileVer : String = "1.1" // data version if (getCheckData != currentDbFileVer) { Toast.makeText(this,"data: $currentDbFileVer",Toast.LENGTH_SHORT).show() lifecycleScope.launch(Dispatchers.IO) { // DO SOMETHING for time works withContext(Dispatchers.IO) { val dbPath: File = applicationContext.getDatabasePath("room_database.db") closeRemoveCopy(dbPath) } } } // write db file version by SharedPreferences editor.putString("getData", currentDbFileVer).apply() }■ Aviso: Independientemente de la función que cree y utilice, lo importante es el orden de cerrar la base de datos, eliminar el archivo de base de datos y copiar el nuevo archivo de base de datos.