You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room:如何在应用首次安装时预填充数据库?

Room首次安装时执行初始化操作的解决方案

已知的Room版本迁移实现

我已经了解Room可以实现数据库版本间的迁移,例如从版本1升级到2的代码如下:

@Database(entities = [FooEntity::class, BarEntity::class], version = 2)
abstract class MyDatabase : RoomDatabase() {

    abstract fun fooDao(): FooDao
    abstract fun barDao(): BarDao
    
    companion object {
        const val DATABASE_NAME: String = "my_database"

        val MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("INSERT INTO foo (id, description) VALUES (1, 'Some text')")
            }
        }
    }
}

使用方式:

Room.databaseBuilder(androidContext(), MyDatabase::class.java, MyDatabase.DATABASE_NAME)
    .fallbackToDestructiveMigration()
    .addMigrations(MIGRATION_1_2)
    .build()

问题:首次安装时执行类似迁移的操作

我尝试创建Migration(0, 1)来在应用首次安装时执行初始化,但未能成功,代码如下:

@Database(entities = [FooEntity::class, BarEntity::class], version = 1)
abstract class MyDatabase : RoomDatabase() {
 
    companion object {
        const val DATABASE_NAME: String = "my_database"

        val MIGRATION_0_1 = object : Migration(0, 1) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("INSERT INTO foo (id, description) VALUES (1, 'Some text')")
            }
        }
    }
}

使用方式:

Room.databaseBuilder(androidContext(), MyDatabase::class.java, MyDatabase.DATABASE_NAME)
    .fallbackToDestructiveMigration()
    .addMigrations(MIGRATION_0_1)
    .build()

另外我试过从应用资产预填充数据库,但遇到了数据库重置的问题,不确定这是否是最佳方案:

Room.databaseBuilder(appContext, MyDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build()

解决方案

1. 为什么Migration(0,1)不生效

Room的Migration仅在已存在的数据库版本升级时触发。首次安装时数据库尚未创建,Room会直接根据实体类生成表结构,不会触发0到1的迁移操作,因此这种方式不可行。

2. 使用RoomDatabase.Callback实现首次初始化

Room提供了RoomDatabase.Callback回调,其中onCreate方法会在数据库首次创建时被调用,正好满足首次安装时执行初始化的需求:

@Database(entities = [FooEntity::class, BarEntity::class], version = 1)
abstract class MyDatabase : RoomDatabase() {

    abstract fun fooDao(): FooDao
    abstract fun barDao(): BarDao

    companion object {
        const val DATABASE_NAME: String = "my_database"

        // 创建数据库回调,处理首次初始化
        private val initCallback = object : RoomDatabase.Callback() {
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                // 执行首次安装需要的初始化操作,比如插入默认数据
                db.execSQL("INSERT INTO foo (id, description) VALUES (1, 'Some text')")
            }
        }

        fun getInstance(context: Context): MyDatabase {
            return Room.databaseBuilder(context, MyDatabase::class.java, DATABASE_NAME)
                .fallbackToDestructiveMigration()
                .addCallback(initCallback) // 添加回调
                .build()
        }
    }
}

如果需要每次打开数据库都执行操作,可以重写onOpen方法,但注意该方法会在每次数据库连接打开时触发,按需选择。

3. 修复预填充数据库的重置问题

若使用createFromAsset出现数据库重置,通常是因为以下原因:

  • 资产中的数据库版本号与@Database注解的version不一致
  • 后续版本升级时未正确处理迁移逻辑

解决方法:

  • 确保资产数据库的版本号和代码中version值完全匹配
  • 若需要在预填充基础上执行额外初始化,可以结合RoomDatabase.Callback的onCreate方法(仅首次创建时执行)或onOpen方法

内容的提问来源于stack exchange,提问作者Leonardo Sibela

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:42:42