0

我想使用 Java Preferences API 为我的应用程序存储一些数据。由于我在 Kotlin 中编写应用程序,因此我想利用委托属性来获取和设置我的偏好。

我目前的设置是这样的

object Pref {
    val systemPref by lazy { Preferences.systemNodeForPackage(App::class.java) }
    val userPref by lazy { Preferences.userNodeForPackage(App::class.java) }

    // example preference
    const val SETTING = "setting"
    var setting: Int
        get() = userPref.getInt(SETTING, -1)
        set(value) = userPref.putInt(SETTING, value)
}

但我想有这样的东西来声明偏好

var setting: Int by preference(userPref, "setting", -1)

API 有不同的方法来访问不同数据类型的首选项。我想使用这些,但它让我的事情变得复杂。有没有办法让这样一个委托可以处理任何数据类型,并且在与库交谈时也不会将所有内容转换为字符串或从字符串转换?

4

1 回答 1

1

您可以使委托的构造函数采用一个KClass参数,您可以检查该参数的类型以获取正确的首选项类型。然后使用类型编写preference函数,reified以便它可以适当地实例化委托。像这样的东西应该可以与您演示的语法一起使用:

inline fun <reified T: Any> preference(preferences: Preferences, key: String, defaultValue: T)
        = PreferenceDelegate(preferences, key, defaultValue, T::class)

class PreferenceDelegate<T: Any>(
    val preferences: Preferences,
    val key: String,
    val defaultValue: T,
    val type: KClass<T>
): ReadWriteProperty<Any, T> {

    @Suppress("UNCHECKED_CAST")
    override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        with (preferences) {
            when (type) {
                Int::class -> putInt(key, value as Int)
                Long::class -> putLong(key, value as Long)
                Float::class -> putFloat(key, value as Float)
                Boolean::class -> putBoolean(key, value as Boolean)
                String::class -> put(key, value as String)
                ByteArray::class -> putByteArray(key, value as ByteArray)
                else -> error("Unsupported preference type $type.")
            }
        }
    }

    @Suppress("UNCHECKED_CAST")
    override fun getValue(thisRef: Any, property: KProperty<*>): T {
        return with (preferences) {
            when (type) {
                Int::class -> getInt(key, defaultValue as Int)
                Long::class -> getLong(key, defaultValue as Long)
                Float::class -> getFloat(key, defaultValue as Float)
                Boolean::class -> getBoolean(key, defaultValue as Boolean)
                String::class -> get(key, defaultValue as String)
                ByteArray::class -> getByteArray(key, defaultValue as ByteArray)
                else -> error("Unsupported preference type $type.")
            }
        } as T
    }

}
于 2021-03-03T19:47:51.587 回答