如何在Hilt ViewModel场景下为Room数据库预填充初始数据
解决方案
你只需要将回调逻辑剥离原有单例实现,直接在Hilt的数据库提供方法中注册回调即可,以下是完整实现步骤:
步骤1:修改PuzzleDatabase添加回调类
你可以直接在数据库类中定义回调,通过原生SQL执行预填充,避免Dao依赖导致的循环依赖问题:
@Database(entities = [Puzzle::class], version = 1, exportSchema = false) abstract class PuzzleDatabase : RoomDatabase() { abstract fun getPuzzleDao() : PuzzleDao class PuzzleDatabaseCallback( private val scope: CoroutineScope ) : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) // 仅在数据库首次创建时执行预填充 scope.launch(Dispatchers.IO) { // 替换为你的Puzzle实体对应的表字段与插入值 db.execSQL("INSERT INTO Puzzle (id, column1, column2, column3) VALUES (0, 9, 5, 'TWO')") } } } }
步骤2:修改AppModule实现回调注册
首先提供应用级协程Scope,再在数据库构造时添加回调即可:
@Module @InstallIn(SingletonComponent::class) object AppModule { // 提供应用生命周期的协程Scope,用于预填充异步操作 @Singleton @Provides fun provideAppCoroutineScope(): CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) @Singleton @Provides fun providePuzzleDatabase( @ApplicationContext app: Context, scope: CoroutineScope ) = Room.databaseBuilder( app, PuzzleDatabase::class.java, "puzzle_database" ) // 注册预填充回调 .addCallback(PuzzleDatabase.PuzzleDatabaseCallback(scope)) .build() @Singleton @Provides fun getDao(db: PuzzleDatabase) = db.getPuzzleDao() }
可选:需要使用Dao执行预填充的实现
如果你不想写原生SQL,非要使用Dao插入,可以通过Hilt EntryPoint规避循环依赖,实现如下:
- 首先定义EntryPoint接口:
@EntryPoint @InstallIn(SingletonComponent::class) interface PuzzleDaoEntryPoint { fun puzzleDao(): PuzzleDao }
- 修改回调类,传入Context并通过EntryPoint获取Dao:
class PuzzleDatabaseCallback( private val context: Context, private val scope: CoroutineScope ) : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) scope.launch(Dispatchers.IO) { val dao = EntryPoints.get( context.applicationContext, PuzzleDaoEntryPoint::class.java ).puzzleDao() dao.insert(Puzzle(0, 9L, 5L, Puzzles.TWO)) } } }
- 注册回调时传入Context即可:
.addCallback(PuzzleDatabase.PuzzleDatabaseCallback(app, scope))
内容的提问来源于stack exchange,提问作者Afterglow
相关产品推荐
相关产品推荐

