【问题标题】:Dagger 2 get own Room instanceDagger 2 获得自己的 Room 实例
【发布时间】:2020-01-17 23:07:22
【问题描述】:

我想向房间数据库添加回调以填充初始数据。

@Provides
@Singleton
fun provideRoom(context: Context): MyRoomDatabase {
    return Room.databaseBuilder(context, MyRoomDatabase::class.java, "my_database")
        .fallbackToDestructiveMigration()
        .addCallback(object : RoomDatabase.Callback() {
            @Override
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)

            }
        })
        .build()
}

为此,我需要回调中的数据库实例来访问 DAO 以插入数据。 这是如何工作的?

编辑:

我想要达到的目标: Create initial data for the room database at the app installation

我的Callback Class

class RoomCallback(
 var myRoomDatabase : MyRoomDatabase
)  : RoomDatabase.Callback()  {
override fun onCreate(db: SupportSQLiteDatabase) {
    myRoomDatabase.basicItemDao().insertList(
        listOf(
            BasicItem(),
            BasicItem()
        )
    )
}

}

我如何提供RoomDatabaseRoomCallback

@Provides
@Singleton
fun provideRoom(context: Context, roomCallback: RoomCallback): MyRoomDatabase {
    return Room.databaseBuilder(context, MyRoomDatabase::class.java, "my_database")
        .fallbackToDestructiveMigration()
        .addCallback(roomCallback)    
        .build()
}

@Provides
@Singleton
fun provideRoomCallback(myRoomDatabase: MyRoomDatabase): RoomCallback {
    return RoomCallback(myRoomDatabase)
}

问题: - RoomCallbackRoomDatabase 实例需要另一个实例。

【问题讨论】:

  • 我认为你可以创建一个 Object(Singleton),在你的基础包中扩展 RoomDatabase.Callback(),然后插入,然后在 addCallback() 中传递该对象
  • @Debanjan 我创建了一个RoomCallback 类并实现了 RoomDatabase.Callback()。现在我想为这个RoomCallback 类提供匕首,但这个类需要 MyRoomDatabase 类。 MyRoomDatabase 类需要 RoomCallback 类。我该如何解决这个问题?
  • @Lingo 我的回答有帮助吗?
  • @Maddy 不抱歉,我知道如何将 Dagger2 与 Room 结合使用。但是在开始时填充数据的部分我遇到了问题。
  • @Lingo 你能用你的问题的更多细节来编辑你的问题吗?

标签: android kotlin android-room dagger-2


【解决方案1】:

更新:使用Kotlin CoroutineDagger2

晚会,但对于未来的读者来说,在创建时或打开时预填充您的数据库非常容易。确保您已经在gradle 文件中为Coroutine 添加了依赖项。首先创建您的数据库,如:

    /**
     * Main database.
     */
    @Database(
        entities = [
            Login::class],
        version = 1,
        exportSchema = false
    )
    abstract class AppDatabase : RoomDatabase() {
        abstract fun loginDao(): LoginDao

        companion object {
            
            @Volatile private var INSTANCE: AppDatabase? = null

            fun getInstance(app: Application): AppDatabase = INSTANCE ?: synchronized(this) {
            INSTANCE ?: buildDatabase(app).also { INSTANCE = it }
        }

        private fun buildDatabase(app: Application) =
            Room.databaseBuilder(app,
                AppDatabase::class.java,
                "your database name")
            .addCallback(object : Callback() {
                // Pre-populate the database after onCreate has been called. If you want to prepopulate at opening time then override onOpen function instead of onCreate.
                override fun onCreate(db: SupportSQLiteDatabase) {
                    super.onCreate(db)
                    // Do database operations through coroutine or any background thread
                    val handler = CoroutineExceptionHandler { _, exception ->
                        println("Caught during database creation --> $exception")
                    }

                    CoroutineScope(Dispatchers.IO).launch(handler) {
                        prePopulateAppDatabase(getInstance(app).loginDao())
                    }
                }
            })
            .build()

        suspend fun prePopulateAppDatabase(loginDao: LoginDao) {
            val admin = Login(0, "Administrator", "1234", 1, isActive = true, isAdmin = true, isLogged = false)
            loginDao.insertLoginData(admin)
        }
    }
}

然后您可以通过将以下代码放置在您的匕首 AppModule 或您希望的单独数据库模块中来提供单例实例。

@Singleton
@Provides
fun provideDb(app: Application): AppDatabase {
    return AppDatabase.getInstance(app)
}

@Singleton
@Provides
fun provideLoginDao(db: AppDatabase): LoginDao {
    return db.loginDao()
}

就是这样,你完成了。在任何地方注入你的单例数据库对象,例如:

@Inject lateinit var loginDao: LoginDao

然后使用它。

【讨论】:

    【解决方案2】:

    先设置数据库

    @Database(
        entities = [User::class],
        version = VERSION_CODE
    )
    abstract class DatabaseManager : RoomDatabase() {
        abstract fun userDao(): UserDao
    }
    

    现在创建一个数据库模块

    @Module
    class DatabaseModule {
    
        @Singleton
        @Provides
        fun provideRoomDatabase(@ApplicationContext context: Context): RoomDatabase {
            return Room.databaseBuilder(context, RoomDatabase::class.java, "dbName")
                .setJournalMode(JournalMode.TRUNCATE)
                .build()
        }
    }
    

    您可以创建一个单独的模块或在DatabaseModule 中添加一个方法,它自提供dao 对象。比如说我有一个UserDao 然后

    @Module
    class UserModule {
    
        @Singleton
        @Provides
        fun provideDao(database: DatabaseManager): UserDao {
            return database.userDao()
        }
    }
    

    【讨论】:

    • .setJournalMode(JournalMode.TRUNCATE) 是做什么的?
    • @EpicPandaForce,请参考this
    • "你想把日志模式显式地改成Truncate,你可以这样做。但是,不建议这样做,因为WAL比Truncate好很多"好吧:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多