web-dev-qa-db-ja.com

Dagger 2を介してRoomDatabaseを提供するときに.addCallback()を実装する適切な方法は何ですか?

Dagger 2を使用して、アプリで必要に応じてRoomDatabaseを作成および共有しています。

データベースのaddCallback()関数をオーバーライドし、それを使用してデータベースの初期値を挿入できるように、onCreate()を実装しようとしています。これは私が問題に直面しているところです。

当たり前のことを見落としているような気がしますが、これを上手に行う方法がわかりません。

RoomDatabaseクラス:

_@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>>

}
_

短剣モジュール:

_@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()

}
_

onCreate()コールバックでDAOにアクセスできるようにしたいと思います。 GoogleがRoomとDaggerを一緒に推進しているため、これが可能であることは明らかであり、これはかなり一般的な使用例である可能性があります。

provideDB()のコンストラクター引数としてDAOを提供しようとしましたが、循環依存関係が作成されます

RoomDatabaseをコンパニオンオブジェクトとして初期化しようとしました。次に、provideDB()メソッドで_Room.builder_形式を使用する代わりに、DAOにアクセスできるgetInstance()メソッドを呼び出すことができます。しかし、このようにして、getWriteableDatabase()への再帰呼び出しでエラーが発生しました。

db.execSQL()のようなものを使用できることは理解していますが、Roomを使用しているときにそれを行うのはとても残念なことのようです。

私が行方不明になっているより良い方法はありますか? Kotlinを使用していますが、Javaの例は大歓迎です。:)

10
Chris Feldman

私はそれを次のように管理しました:

@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()

}

ただし、dbを開始してonCreate()を呼び出すには、データベースから偽の読み取りを行う必要があることに注意してください。 dbが作成されていないときは、最初の対話としてdbに書き込まないでください。競合状態が発生し、作成時の書き込みが有効になりません。

2
Amir

あなたは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;
0
Sushobh Nadiger

最終的な1要素配列を作成できます。

@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];
}
0
michal3377