I am using Android Room in an app. I have a pre-build database in assets which I need to use. Each time i update the version i need to replace old db with new DB. For this I have copied the database with conventional file 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()
}
}
}
Here is the getter for Database instance :-
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
}
Migration is Empty for now cause i need to wipe out old one a copy new one. So i think migration is not required for this .
@JvmField
val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
}
}
First time all working fine. When I upgrade the version of database I am deleting the old file copy new file, but Room is returning the old data. I am not sure what's the problem.
I even tried some older answer which suggests:
How to use Room Persistence Library with pre-populated database? library-with-pre-populated-database
Also tried some other stuff from Git, but none of it worked. What could be the issue? My need is replace old database with new one each time database version is upgrade.
The safest and most complete method:
Make fun 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)
}
And make fun 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()
}
}
And 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()
}
■ Notice: Whatever function you create and use, the important thing is the order of closing DB, deleting DB-file, and copying the new DB-file.