[英]What is the proper way to implement .addCallback() when providing RoomDatabase via Dagger 2?
I'm using Dagger 2 to create and share my RoomDatabase where necessary in my app.我正在使用 Dagger 2 在我的应用程序中根据需要创建和共享我的 RoomDatabase。
I'm trying to implement addCallback()
so I can override the database's onCreate()
function and use it to insert my initial database values.我正在尝试实现
addCallback()
以便我可以覆盖数据库的onCreate()
函数并使用它来插入我的初始数据库值。 This is where I'm running into issues.这是我遇到问题的地方。
I feel like I have to be overlooking something obvious, but I can't figure out a way to do this gracefully.我觉得我必须忽略一些明显的事情,但我无法找到一种优雅地做到这一点的方法。
RoomDatabase class:房间数据库类:
@Database(
entities = [Station::class],
version = 1,
exportSchema = false
)
abstract class TrainDB : RoomDatabase() {
abstract fun stationDao() : StationDao
}
DAO:道:
@Dao
abstract class StationDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insert(stations: Station)
@Query("SELECT * FROM station_table")
abstract fun getAll() : LiveData<List<Station>>
}
Dagger Module:匕首模块:
@Module
class DataModule {
@Singleton
@Provides
fun provideDb(app: Application): TrainDB {
var trainDB: TrainDB? = null
trainDB = Room
.databaseBuilder(app, TrainDB::class.java, "train.db")
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
/*
WHAT GOES HERE?
*/
}
})
.build()
return trainDB
}
@Singleton
@Provides
fun providesStationDao(db: TrainDB) : StationDao = db.stationDao()
}
I'd like to be able to access my DAO in the onCreate()
callback.我希望能够在
onCreate()
回调中访问我的 DAO。 It seems obvious that this should be possible because Google is pushing Room and Dagger together and this is likely a pretty common use case.很明显,这应该是可能的,因为 Google 正在将 Room 和 Dagger 放在一起,这可能是一个非常常见的用例。
I've tried providing the DAO as a constructor argument for provideDB()
, but that creates a circular dependency我尝试将 DAO 作为
provideDB()
的构造函数参数提供,但这会创建循环依赖
I've tried initializing my RoomDatabase as a companion object.我尝试将我的 RoomDatabase 初始化为伴随对象。 Then instead of using the
Room.builder
format in my provideDB()
method, I can call a getInstance()
method that has access to the DAO.然后,我可以调用可以访问 DAO 的
getInstance()
方法,而不是在我的provideDB()
方法中使用Room.builder
格式。 But this way I'm met with an error for a recursive call to getWriteableDatabase()
.但是通过这种方式,我遇到了递归调用
getWriteableDatabase()
的错误。
I understand that I can use something like db.execSQL()
, but it seems like such a shame to do that when I'm using Room.我知道我可以使用类似
db.execSQL()
的东西,但是当我使用 Room 时这样做似乎太可惜了。
Is there a better way that I'm missing?有没有更好的方法让我想念? I'm using Kotlin, but Java examples are welcome.
我正在使用 Kotlin,但欢迎使用 Java 示例。 :)
:)
I have managed it like this: 我已经这样管理:
@Module
class DataModule {
lateinit var trainDB: TrainDB
@Singleton
@Provides
fun provideDb(app: Application): TrainDB {
trainDB = Room
.databaseBuilder(app, TrainDB::class.java, "train.db")
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
/*
trainDB.stationDao().insert(...)
*/
}
})
.build()
return trainDB
}
@Singleton
@Provides
fun providesStationDao(db: TrainDB) : StationDao = db.stationDao()
}
But remember You need to to do a fake read from the database in order to initiate the db and invoke onCreate(). 但是请记住,您需要从数据库中进行虚假读取,以启动数据库并调用onCreate()。 don't write into db as your first interact when db hasn't been created because it will create a race condition and your on create writing won't take effect.
当尚未创建db时,请勿在第一次交互时写入db,因为这会创建竞争条件,并且您在创建时的写入不会生效。
You can do this in java 您可以在Java中执行此操作
AppDatabase appDatabase = null;
AppDatabase finalAppDatabase = appDatabase;
appDatabase = Room.databaseBuilder(MyApplication.getApplication(),
AppDatabase.class, Constants.DATABASE_NAME).
addCallback(new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
//check for null
finalAppDatabase.yourDao();
}
}).
build();
return appDatabase;
You can create final one-element array. 您可以创建最终的一元素数组。
@AppScope
@Provides
public AppDatabase appDatabase(@ApplicationContext Context appContext, AppExecutors executors) {
final AppDatabase[] databases = new AppDatabase[1];
databases[0] = Room.databaseBuilder(appContext, AppDatabase.class, AppDatabase.DATABASE_NAME)
.fallbackToDestructiveMigration()
.addCallback(new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
executors.diskIO().execute(() -> {
databases[0].populateDatabaseOnCreate();
});
}
}).build();
return databases[0];
}
We can inject lazily to prevent circular dependency.我们可以惰性注入来防止循环依赖。
For example例如
@Singleton
@Provides
fun provideDb(
app: Application,
trainDBLazy: Lazy<TrainDB> // import dagger.Lazy
): TrainDB {
return Room
.databaseBuilder(app, TrainDB::class.java, "train.db")
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
var trainDB = trainDBLazy.get()
}
})
.build()
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.