Как правильно реализовать .addCallback () при предоставлении RoomDatabase через Dagger 2? - PullRequest
0 голосов
/ 25 мая 2018

Я использую 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()

}

Я хотел бы иметь возможность получить доступ к своему DAO в обратном вызове onCreate().Кажется очевидным, что это должно быть возможно, потому что Google объединяет Room и Dagger, и это, вероятно, довольно распространенный вариант использования.

Я пытался предоставить DAO в качестве аргумента конструктора для provideDB(), но этосоздает циклическую зависимость

Я попытался инициализировать мою RoomDatabase как объект-компаньон.Затем вместо использования формата Room.builder в моем методе provideDB() я могу вызвать метод getInstance(), который имеет доступ к DAO.Но в этом случае я получаю сообщение об ошибке для рекурсивного вызова getWriteableDatabase().

. Я понимаю, что могу использовать что-то вроде db.execSQL(), но мне кажется, что мне стыдно делать это, когда я 'Я использую Комнату.

Есть ли лучший способ, который я пропускаю?Я использую Kotlin, но примеры Java приветствуются.:)

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Вы можете создать окончательный одноэлементный массив.

@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 голосов
/ 29 августа 2018

Мне удалось это так:

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

}

Но помните, что вам нужно сделать ложное чтение из базы данных, чтобы инициировать БД и вызвать onCreate ().не пишите в db как ваше первое взаимодействие, когда db не был создан, потому что это создаст условия гонки, и ваши записи при создании не вступят в силу.

0 голосов
/ 25 мая 2018

Вы можете сделать это в 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;
...