Java 具有 Kotlin 委托属性的首选项 API
Java Preferences API with Kotlin delegated properties
我想使用 Java 首选项 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有不同的方法来访问不同数据类型的首选项。我想使用那些,但它使我的事情变得复杂。有没有一种方法可以让这样一个委托可以处理任何数据类型,并且在与库对话时也不会将所有内容与字符串相互转换?
您可以让委托的构造函数接受一个 KClass
参数,您可以检查该参数的类型以返回正确的偏好类型。然后使用 reified
类型编写 preference
函数,以便它可以适当地实例化委托。像这样的东西应该可以用于您演示的语法:
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
}
}
我想使用 Java 首选项 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有不同的方法来访问不同数据类型的首选项。我想使用那些,但它使我的事情变得复杂。有没有一种方法可以让这样一个委托可以处理任何数据类型,并且在与库对话时也不会将所有内容与字符串相互转换?
您可以让委托的构造函数接受一个 KClass
参数,您可以检查该参数的类型以返回正确的偏好类型。然后使用 reified
类型编写 preference
函数,以便它可以适当地实例化委托。像这样的东西应该可以用于您演示的语法:
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
}
}