Тип комнаты Android конвертировать несколько типов перечислений - PullRequest
0 голосов
/ 29 июня 2018

Я пишу конвертер типов для своей базы данных Room. У меня есть пара пользовательских классов enum, и я хочу преобразовать их в порядковые номера при сохранении в базе данных. Таким образом, вместо написания следующего для каждого отдельного класса, есть ли способ упростить его (например, передать универсальный тип enum)?

class Converter {

    @TypeConverter
    fun toOrdinal(type: TypeA): Int = type.ordinal

    @TypeConverter
    fun toTypeA(ordinal: Int): TypeA = TypeA.values().first { it.ordinal == ordinal }

    @TypeConverter
    fun toOrdinal(type: TypeB): Int = type.ordinal

    @TypeConverter
    fun toTypeB(ordinal: Int): TypeB = TypeB.values().first { it.ordinal == ordinal }

    ...
}

Ответы [ 2 ]

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

Вы можете использовать составной интерфейс для достижения этой цели, поскольку вы не можете написать один класс конвертера для нескольких типов объектов. Это отчасти хакерство, но может сработать:

interface BaseType {
    val arg0: String

    fun asString() : String? {
        return when(this) {
            is TypeA -> "${TypeA::class.simpleName}$separatorParam$arg0"
            is TypeB -> "${TypeB::class.simpleName}$separatorParam$arg0"
            else -> null
        }
    }

    companion object {
        const val separatorParam = "::"
    }
}

enum class TypeA (override val arg0: String) : BaseType {
    A_ONE("argument 1"),
    A_TWO("argument 2");

    companion object {
        fun getValueTypes(arg0: String) : TypeA? = values().firstOrNull { it.arg0 == arg0 }
    }
}

enum class TypeB (override val arg0: String) : BaseType {
    A_ONE("argument 1"),
    A_TWO("argument 2");

    companion object {
        fun getValueTypes(arg0: String) : TypeB? = values().firstOrNull { it.arg0 == arg0 }
    }
}

class Converter {
    @TypeConverter
    fun fromBaseType(type: BaseType) : String? = type.asString()

    @TypeConverter
    fun toBaseType(param: String?) : BaseType? = param?.asBaseType()

    private fun String.asBaseType() : BaseType? {
        val stringArray = this.split(BaseType.separatorParam)
        val className : String? = stringArray[0]
        return when(className) {
            TypeA::class.simpleName -> TypeA.getValueTypes(stringArray[1])
            TypeB::class.simpleName -> TypeB.getValueTypes(stringArray[1])
            else -> null
        }
    }
}

Тогда вам нужна функция в вашем data class, чтобы предоставить вам фактический TypeA или TypeB

data class MyDbModel(val baseType: BaseType) {
    inline fun <reified T: BaseType> getTypeAs() : T? = 
            when(baseType) {
                is TypeA -> TypeA.getValueTypes(baseType.arg0) as? T
                is TypeB -> TypeB.getValueTypes(baseType.arg0) as? T
                else -> null
            }
}

fun foo() {
    val model = MyDbModel(TypeA.A_ONE)
    val type = model.getTypeAs<TypeA>()
}

Недостатком этого является то, что он работает только для уникального arg0 в пределах определенного перечисления, для этого вы можете использовать порядковый номер или вы можете использовать сгенерированный идентификатор, такой как R.id.a_one, в качестве первого параметра, а затем второй параметр может быть вашим строка.

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

Как обсуждено здесь , Room не может обрабатывать универсальные конвертеры в данный момент. Я думаю, что лучшее, что вы можете сделать, - это создать расширения, которые ускорят написание этих enum-конвертеров:

@Suppress("NOTHING_TO_INLINE")
private inline fun <T : Enum<T>> T.toInt(): Int = this.ordinal

private inline fun <reified T : Enum<T>> Int.toEnum(): T = enumValues<T>()[this]

Это упростит каждую пару преобразователей в этот код:

@TypeConverter fun myEnumToTnt(value: MyEnum) = value.toInt()
@TypeConverter fun intToMyEnum(value: Int) = value.toEnum<MyEnum>()

Или, если вы можете хранить нулевые значения:

@TypeConverter fun myEnumToTnt(value: MyEnum?) = value?.toInt()
@TypeConverter fun intToMyEnum(value: Int?) = value?.toEnum<MyEnum>()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...