简体   繁体   English

通过 Dagger 2 提供 RoomDatabase 时实现 .addCallback() 的正确方法是什么?

[英]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.

相关问题 实现 SharedPreferencesBackupHelper 的正确方法是什么? - What is the proper way to implement SharedPreferencesBackupHelper? 使用 Dagger 时在 Epoxy Controller 内实现 onClick 的最佳方法是什么 - What is the best way to implement onClick inside an Epoxy Controller when using Dagger 什么是在MvvmCross 3.5.1中实现Fragments的正确方法 - What's the proper way to implement Fragments in MvvmCross 3.5.1 实现具有动态绘制内容的 Android 小部件的正确方法是什么? - What's the proper way to implement an Android widget with dynamically drawn content? 在 Android 上实现可恢复调度程序的正确方法是什么? - What's the proper way to implement resumable scheduler on Android? Dagger 2-提供应用程序类 - Dagger 2 - Providing Application class Dagger:定义可在其构造函数中获取上下文的可注入类的正确方法 - Dagger: proper way to define injectable class that takes context in its constructor 在android中实现服务的正确方法 - Proper way to implement services in android 使用 Dagger 2 注入子类的最佳方法是什么? - What is the best way to inject subclasses using Dagger 2? 如何使用 RoomDatabase 实现搜索功能 - How Can I Implement Search Function with RoomDatabase
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM