android - 使用 Hilt 预填充 Room 数据库,而无需创建额外的数据库实例

标签 android android-room dagger-hilt

我试图确保我的数据库始终包含一个初始行。我通读了 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 中的循环依赖,您可以依赖 ProviderLazy :

    @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/

相关文章:

java - 从 jsonArray java android 获取字符串

android - ADT Eclipse(Juno) 中缺少向虚拟设备添加自定义 android 皮肤

Android 架构组件 liveData 和 room - 最低要求是什么?

android - 在 Android 项目中添加 Hilt 组件后构建失败

java - 由于快照依赖性(?),Gradle 同步失败(Android Studio)

java - Android - Scrollview 中的 Gridview 问题

java - 如何正确解析数据或使用 Room 数据?

android - 添加Android Room库(jcenter给出404错误)

android - Hilt - 如何注入(inject) ViewModel 接口(interface)?

android - 使用带有挂起功能 block 的接口(interface)类的 Hilt 进行依赖注入(inject)