问题
I want to add a callback to the room database to populate initial data.
@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()
}
For that i need the database instance in the callback to access DAO for inserting data. How does this work?
EDIT:
What I want to achieve:
Create initial data for the room database at the app installation
My Callback Class
:
class RoomCallback(
var myRoomDatabase : MyRoomDatabase
) : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
myRoomDatabase.basicItemDao().insertList(
listOf(
BasicItem(),
BasicItem()
)
)
}
}
How i provide the RoomDatabase
and the RoomCallback
:
@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)
}
PROBLEM:
- The RoomCallback
and RoomDatabase
instance need both the other instance.
回答1:
Setup a database first
@Database(
entities = [User::class],
version = VERSION_CODE
)
abstract class DatabaseManager : RoomDatabase() {
abstract fun userDao(): UserDao
}
Now create a DatabaseModule
@Module
class DatabaseModule {
@Singleton
@Provides
fun provideRoomDatabase(@ApplicationContext context: Context): RoomDatabase {
return Room.databaseBuilder(context, RoomDatabase::class.java, "dbName")
.setJournalMode(JournalMode.TRUNCATE)
.build()
}
}
You can create a separate module or add a method in DatabaseModule
it self providing dao object. Say for example I have a UserDao
then
@Module
class UserModule {
@Singleton
@Provides
fun provideDao(database: DatabaseManager): UserDao {
return database.userDao()
}
}
回答2:
Late in the party but for future readers, it's very easy to prepopulate your database at creation time or openning time. First create your database like:
/**
* 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)
}
}
}
Then you can provide singleton instance by placing below code to your dagger
AppModule
or in a separate database module as you wish.
@Singleton
@Provides
fun provideDb(app: Application): AppDatabase {
return AppDatabase.getInstance(app)
}
@Singleton
@Provides
fun provideLoginDao(db: AppDatabase): LoginDao {
return db.loginDao()
}
that's it, you are done. Inject anywhere your singleton database object like:
@Inject lateinit var loginDao: LoginDao
then use it.
来源:https://stackoverflow.com/questions/57968242/dagger-2-get-own-room-instance