我试图确保我的数据库始终包含一个初始行。我通读了 How to populate Android Room database table on first run?我遇到的主要问题是,在创建数据库时,我无法使用 Hilt 访问(或者我不知道如何访问它?)。如果我尝试重新使用我编写的 provideDatabase
Hilt 方法,它会导致 SQLite 数据库泄漏(可能是因为周围没有人使用这些生成的实例来关闭数据库)。这是我的代码:
@Module
@InstallIn(ApplicationComponent::class)
object AppModule {
@Singleton
@Provides
fun provideDatabase(@ApplicationContext context: Context): GameDatabase {
return Room.databaseBuilder(context, GameDatabase::class.java, GameDatabase.GAME_DB_NAME)
.addCallback(
object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
// Initialize the database with the first game
ioThread {
provideDatabase(context).gameDao().createNewGame(Game())
}
}
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
// Ensure there is always one game in the database
// This will capture the case of the app storage
// being cleared
// THIS results in an instance being created that can't be closed - causing DB leaks!
ioThread {
val gameDao = provideDatabase(context).gameDao()
if (gameDao.gameCount() == 0) {
gameDao.createNewGame(Game())
}
}
}
}
).build()
}
@Singleton
@Provides
fun provideGameDao(database: GameDatabase): GameDao {
return database.gameDao()
}
}
那么,我如何获得我的 DAO 来进行初始化呢?我是否只需要在 SQL 中手动制作插入语句并在数据库中调用它?
最佳答案
您的 provideDatabase
方法总是在每次调用时创建一个新实例:Dagger 通过仅调用该方法一次使其成为单例。获取由 ApplicationComponent
管理的单例 GameDatabase
实例的唯一方法是将其作为依赖项进行请求。由于 GameDatabase
需要通过 GameDao
依赖自身,这是一个循环依赖。
要解决 Dagger 中的循环依赖,您可以依赖 Provider
或 Lazy
:
@Singleton
@Provides
fun provideDatabase(@ApplicationContext context: Context, gameDaoProvider: Provider<GameDao>): GameDatabase {
return Room.databaseBuilder(context, GameDatabase::class.java, GameDatabase.GAME_DB_NAME)
.addCallback(
object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
// Initialize the database with the first game
ioThread {
gameDaoProvider.get().createNewGame(Game())
}
}
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
// Ensure there is always one game in the database
// This will capture the case of the app storage
// being cleared
// This uses the existing instance, so the DB won't leak
ioThread {
val gameDao = gameDaoProvider.get()
if (gameDao.gameCount() == 0) {
gameDao.createNewGame(Game())
}
}
}
}
).build()
}
关于android - 使用 Hilt 预填充 Room 数据库,而无需创建额外的数据库实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65803302/