首页 > 解决方案 > Android Room 预填充 SQL 数据库并持久更新

问题描述

我正在尝试使用 Kotlin 来:
- 从现有 SQL 数据库预填充我的应用程序中的房间数据库。
- 允许用户更新数据。
- 让更新的数据只保留当前版本。
- 让新版本清除旧数据并用新发布的 SQL 数据库替换它。

这是我到目前为止所做的:
我使用createFromAsset方法通过调用预填充数据库,fallbackToDestructiveMigration()如下所示:

@Database(entities = [MCData::class], version = 1, exportSchema = false)
abstract class MyRoom : RoomDatabase() {
    abstract val myDao: MyDao

    companion object {

        @Volatile 
        private var INSTANCE: MyRoom? = null

        fun getInstance(context: Context): MyRoom {

            synchronized(this) {

                var instance = INSTANCE

                if (instance == null) {

                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        MyRoom::class.java,
                        "mcdata.db")
                        .createFromAsset("mydata.db")
                        .fallbackToDestructiveMigration()
                        .build()
                    INSTANCE = instance
                }

                return instance
            }
        }
    }

这是预先填充数据并让用户更改它,但是当应用程序重新启动时,初始填充后数据中的更新会丢失。我对这种行为感到困惑,因为fallbackToDestructiveMigration()即使架构没有更改(用户只能更改两个现有列的值),代码似乎也在使用 刷新数据。

如果我删除该fallbackToDestructiveMigration()方法,则初始预填充后用户的更新仍然存在,但是当我使用新数据重新安装应用程序时,数据库不会更新。

有没有办法让数据(包括编辑)保留在当前版本中,但在安装新版本时被新的预填充 SQL 数据库替换?

标签: androidkotlinmigrationpersistence

解决方案


我最终创建了两个构建器函数:
- 第一个在第一次安装或更新软件时调用,它从资产数据库中读取。
- 第二个在其他时候被调用,它从本地创建的数据库中读取,因此用户的小调整会持续到版本中。

@Database(entities = [MCData::class,FBData::class,WhereAmIdata::class], version = 1, exportSchema = false)
abstract class MyRoom : RoomDatabase() {
    abstract val myDao: MyDao

    companion object {

        @Volatile // with volatile, changes immediately become visible to all threads
        private var INSTANCE: MyRoom? = null

        // this instantiaion is called the first time the software is updated
        fun getInstanceAfterSoftwareUpdate(context: Context): MyRoom {

            synchronized(this) {
                var instance = INSTANCE

                if (instance == null) {
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        MyRoom::class.java,
                        "mcdata")
                        .createFromAsset("mydata.db")
                        .fallbackToDestructiveMigration()
                        .build()

                    INSTANCE = instance
                }
                return instance
            }
        }


        fun getInstance(context: Context): MyRoom {

            synchronized(this) {

                var instance = INSTANCE

                if (instance == null) {

                    Log.i("MyRoom", "reading locally")
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        MyRoom:: class.java,
                        "mcdata"
                    )
                        .fallbackToDestructiveMigration()
                        .build()

                    INSTANCE = instance
                }

                return instance
            }
        }
    }
}

推荐阅读