Тип помещения: Преобразователь с конструктором

У меня есть Room TypeConverter, и мне нужно ввести параметр в его конструктор

class RoomConverters(moshi Moshi) {

    @TypeConverter
    fun fromUserActionLog(data: UserActionLogModel): String {
        return moshi.adapter(UserActionLogModel::class.java).toJson(data)
    }

    @TypeConverter
    fun toUserActionLog(json: String): UserActionLogModel {
        return moshi.adapter(UserActionLogModel::class.java).fromJson(json)}
    }
}

Но когда я не могу аннотировать TypeConverter для объекта базы данных с помощью конструктора;

@Database(entities = [SsidModel::class], version = 1, exportSchema = false)
@TypeConverters(RoomConverters::class)   
abstract class AppDatabase : RoomDatabase() {

    abstract fun ssidDao(): SsidDao
}

Есть ли способ добиться этого?

11
0
2 156
5

Ответы 5

Я использую dagger-android и столкнулся с той же проблемой. Решение - при создании базы данных приложений

@Provides @Reusable
fun provideDatabase(context: Context, moshi: Moshi): AppDatabase = 
    Room.databaseBuilder(...).build().apply { AppDatabase.moshi = moshi }

AppDatabase - это просто RoomDatabase:

@Database(
    entities = [OrderEntity::class],
    version = 1,
    exportSchema = false
)
@TypeConverters(DbConverters::class)
abstract class AppDatabase : RoomDatabase() {
    companion object {
        lateinit var moshi: Moshi
    }

    abstract fun orderDao(): OrderDao
}

Затем используйте этот сопутствующий объект в конвертере:

class DbConverters {

    @TypeConverter
    fun orderInfoToString(orderInfo: OrderInfo?): String? = 
           AppDatabase.moshi.adapter(OrderInfo::class.java).toJson(orderInfo)

    @TypeConverter
    fun stringToOrderInfo(value: String): OrderInfo? = 
          AppDatabase.moshi.adapter(OrderInfo::class.java).fromJson(value)
}

Я думаю, это выглядит некрасиво, но работает. Возможно, использование статического / сопутствующего объекта с областью @Reuseable - плохая идея. Moshi, однако, предоставляется с использованием области видимости @Singleton в AppModule, поэтому в основном проживает всю жизнь приложения.

Я проверил документацию даже на последнюю версию rc (2.2.0-rc01), и нет возможности сделать это. Я думаю, это шутка, что мы не можем зарегистрировать пользовательские преобразователи типов в DatabaseBuilder, поэтому я создал ошибку для этого в Система отслеживания проблем Google.

По состоянию на 11 августа 2020 года Google по-прежнему не исправляет это. А пока проверьте любой из этих обходных путей.

https://issuetracker.google.com/issues/142086380https://issuetracker.google.com/issues/121067210

К счастью, версия 2.3.0 Room, выпущенная 21 апреля 2021 года, теперь поддерживает эту возможность.

Gitahi Ng'ang'a 23.04.2021 20:28

Вы можете создать Room TypeConverter с параметрами конструктора из версии 2.3.0-alpha03

Примечания к выпуску:

Room now has APIs for providing instances of type converters such that the app can control their initialization. To mark a type converter that will be provided to Room use the new annotation @ProvidedTypeConverter

https://developer.android.com/jetpack/androidx/releases/room#2.3.0-alpha03

В вашем случае вы должны добавить @ProvidedTypeConverter в RoomConverter

@ProvidedTypeConverter    
class RoomConverters(moshi: Moshi)

Создайте конвертер во время создания базы данных и передайте его построителю базы данных:

val roomConverter = RoomConverters(Moshi())
val db = Room.databaseBuilder()
         .addTypeConverter(roomConverter)
         .build()

Также вы можете использовать структуру DI, например. Кинжал2

Теперь, когда выпущена библиотека Room 2.3.0. Можно создать экземпляры преобразователей типа Room и предоставить их построителю базы данных.

Добавьте аннотацию @ProvidedTypeConverter к классу TypeConverter.

@ProvidedTypeConverter
class RoomConverter(moshi Moshi) {

    @TypeConverter
    fun fromUserActionLog(data: UserActionLogModel): String {
        return moshi.adapter(UserActionLogModel::class.java).toJson(data)
    }

    @TypeConverter
    fun toUserActionLog(json: String): UserActionLogModel {
        return moshi.adapter(UserActionLogModel::class.java).fromJson(json)}
    }
}

Упомяните TypeConverter в аннотации @TypeConverter абстрактного класса базы данных.

@Database(entities = [/* entities here */], version = 1, exportSchema = false)
@TypeConverters(RoomConverters::class)   
abstract class AppDatabase : RoomDatabase() {
    ......
    // your code here
    ......
}

Теперь создайте базу данных, используя статический метод databaseBuilder класса Room, и предоставьте TypeConverter, используя метод addTypeConverter().

val roomConverter = RoomConverter(moshi)
val appDb = Room.databaseBuilder(
                            applicationContext,
                            AppDatabase::class.java, DB_NAME
                        )
                            .addTypeConverter(roomConverter)
                            .build()

Другие вопросы по теме