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
相关产品推荐
相关产品推荐

