【问题标题】:Pre-populating Room database with Hilt without creating an extra instance of the database使用 Hilt 预填充 Room 数据库,无需创建额外的数据库实例
【发布时间】:2021-04-24 10:47:28
【问题描述】:

我试图确保我的数据库始终包含一个初始行。我通读了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 中手动制作一个插入语句并在数据库上调用它?

【问题讨论】:

    标签: android android-room dagger-hilt


    【解决方案1】:

    您的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()
        }
    

    【讨论】:

    • 谢谢,这很有魅力。不再有关于内存泄漏的 SQLiteDatabase 丑陋警告!感谢您的快速帮助。
    • 出现错误:以递归方式指向 daopprovider.get()
    【解决方案2】:

    有一个问题:

    @Singleton
    @Provides
    fun provideGameDao(database: GameDatabase): GameDao {
        return database.gameDao()
    }
    

    应该是:

    @Provides
    fun provideGameDao(database: GameDatabase): GameDao {
        return database.gameDao()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-27
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2012-11-03
      相关资源
      最近更新 更多