Как получить значение перечисления с помощью дженериков? - PullRequest
0 голосов
/ 30 ноября 2018

Я хочу предоставить контекст для этого вопроса.Я видел уникальные решения, в которых люди создают делегатов, которые будут читать / писать из SharedPreferences вместо вспомогательного поля.Чтобы сделать это для строки, например:

class SharedPrefsString(private val sharedPrefs: SharedPreferences) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return sharedPrefs.getString(property.name, "")
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        sharedPrefs.edit().putString(property.name, value).apply()
    }
}

var myString: String by SharedPrefsString(myPrefs)

Однако я надеялся, что смогу сделать то же самое с универсальным перечислением, так как все перечисления имеют метод valueOf(string), но нижеприведенное не делаетт работа.В комментариях я добавил несколько вещей:

class SharedPrefsEnum<T : Enum<T>>(private val sharedPrefs: SharedPreferences) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        // Doesn't work, can't reference T, which makes sense. 
        // return T.valueOf(sharedPrefs.getString(property.name, ""))

        // Can't use reified type here, which makes sense.
        // return enumValueOf<T>(sharedPrefs.getString(property.name, ""))
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        sharedPrefs.edit().putString(property.name, value.name).apply()
    }
}

var myEnum: MyEnum by SharedPrefsEnum(myPrefs)

Возможно ли что-то подобное?

Ответы [ 3 ]

0 голосов
/ 30 ноября 2018

Мне удалось решить это с помощью отражения.Спасибо Зои за то, что указал мне правильное направление.

Мне также пришлось перейти в класс для перечисления, но с помощью этого я смог найти valueOf с помощью отражения и вызвать его со строкой, которую я получаю из предпочтений.

class SharedPrefsEnum<T : Enum<T>>(private val sharedPrefs: SharedPreferences, private val clazz: Class<T>) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val prefsString = sharedPrefs.getString(property.name, "")
        val method = clazz.getDeclaredMethod("valueOf", String::class.java)
        return method.invoke(null, prefsString) as T
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        sharedPrefs.edit().putString(property.name, value.name).apply()
    }
}
0 голосов
/ 30 ноября 2018

Построив свой ответ, вы можете избежать использования отражения, используя свойство enumConstants:

class SharedPrefsEnum<T : Enum<T>>(
    private val sharedPrefs: SharedPreferences, 
    private val clazz: Class<T>
) : ReadWriteProperty<Any, T> {
    operator fun getValue(thisRef: Any, property: KProperty<*>): T {
        val enumName = sharedPrefs.getString(property.name, "")
        return clazz.enumConstants.find { it.name == enumName }!!
    }

    operator fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        sharedPrefs.edit().putString(property.name, value.name).apply()
    }
}

Затем вы можете легко добавить делегата, используя:

inline fun <reified T : Enum<T>> sharedPreferences(prefs: SharedPreferences) = 
    SharedPrefsEnum(prefs, T::class.java)

Позволяя вамназначить его с помощью:

private var myEnum: MyEnum by sharedPreferences(preferences)

Однако вы можете захотеть сделать тип свойства обнуляемым, как если бы ваш SharedPreferences не содержал значения, это вызовет исключение при доступе к значению.

0 голосов
/ 30 ноября 2018

Я использую это:

var lastUpdate by PersistedProperty("lastUpdate",0L)

и это реализация:

class PersistedProperty<T>(var prefName:String, var default: T)
{
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value!!
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T){
        this.value=value
    }

    fun getFresh():T
    {
        value = getPreference(prefName, default)
        return value!!
    }

    var value:T? = null
        get(){
            if(field==null)
                field=getPreference(prefName, default)
            return field
        }
        set(value){
            if(value==field)
                return
            savePreference(prefName, value)
            field=value
        }

}

fun<T> savePreference(name:String, value:T,prefFile: String? = null)
{
    val sharedPreferences = App.instance.getSharedPreferences(prefFile?:App.instance.packageName+ "_preferences",Context.MODE_PRIVATE)
    when(value)
    {
        is String->sharedPreferences.edit().putString(name, value).apply()
        is Int->sharedPreferences.edit().putInt(name, value).apply()
        is Long->sharedPreferences.edit().putLong(name, value).apply()
        is Float->sharedPreferences.edit().putFloat(name, value).apply()
        is Boolean->sharedPreferences.edit().putBoolean(name, value).apply()
        else -> throw(Exception("Not suported type"))
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...