一,属性委托
有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现他们,但是如果能够为大家把他们只实现一次并放入一个库会更好,例如包括
- 延迟属性(lazy properties):其值只在首次访问时计算
- 可观察性属性(observable properties):监听器会收到此属性变更的通知
- 把多个属性存储在一个映射(map)中,而不是存在没个单独字段中
为了涵盖这些(以及其他)情况,kotlin支持委托属性:
语法是:val/var<属性名>:<类型> by <表达式> 在by后面的表达式是该委托,因为属性对应的get()和set()会被委托给它的getValue()和setValue()方法,属性的委托不必实现任何的接口,但是需要提供一个getValue()和setValue()->对于var属性
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name} in $thisRef.'")
}
}
class Example{
val d = Delegate()
val e = Delegate()
var p: String by d
var l: String by e
}
fun main(args: Array<String>){
val e = Example()
println(e.p)
e.p = "NEW"
println(e.l)
e.l = "NEW.L"
println(e.d)
println(e.e)
}
输出结果:
com.xp.kotlin.part1.Example@300ffa5d, thank you for delegating ‘p’ to me!
NEW has been assigned to ‘p in com.xp.kotlin.part1.Example@300ffa5d.’
com.xp.kotlin.part1.Example@300ffa5d, thank you for delegating ‘l’ to me!
NEW.L has been assigned to ‘l in com.xp.kotlin.part1.Example@300ffa5d.’
com.xp.kotlin.part1.Delegate@1f17ae12
com.xp.kotlin.part1.Delegate@4d405ef7
当我们从委托到一个Delegate示例的p读取是,将调用Delegate中的getValue()函数,所以它的第一个参数是读出p的对象,第二个参数保存了对p自身的表述(例如你可以取它的名字)
从上面输出我们可以看出 每次委托的时候都要new新的对象。
二,委托属性之SharedPreferences工具类应用
有了属性委托,当我们在用Kotlin写SharedPreferences工具类的时候,就会变得更加简单和易读。
class Preference<T>(private val key: String, private val default: T) : ReadWriteProperty<Any?, T> {
companion object {
val preference: SharedPreferences by lazy { BaseApplication.INSTANCE.applicationContext.getSharedPreferences(Constant.SHARED_NAME, Context.MODE_PRIVATE) }
fun clear() {
preference.edit().clear().apply()
}
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return getSharePreference(key, default)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
return putSharePreference(key, value)
}
@Suppress("UNCHECKED_CAST")
private fun <T> getSharePreference(key: String, default: T): T = with(preference) {
val value: Any = when (default) {
is Long -> getLong(key, default)
is String -> getString(key, default)
is Int -> getInt(key, default)
is Boolean -> getBoolean(key, default)
is Float -> getFloat(key, default)
else -> throw IllegalArgumentException("This type of data can not be saved! ")
}
value as T
}
@SuppressLint("CommitPrefEdits")
private fun <T> putSharePreference(key: String, default: T) = with(preference.edit()) {
when (default) {
is Long -> putLong(key, default)
is String -> putString(key, default)
is Int -> putInt(key, default)
is Boolean -> putBoolean(key, default)
is Float -> putFloat(key, default)
else -> throw IllegalArgumentException("This type of data can not be saved! ")
}.apply()
}
}
我们知道SharedPreference是用来存储一些基本数据类型的数据的。当我们存储指定数据类型的时候。我们可以使用泛型并在when中进行判断。然后进行get和put操作。
private var isLogin: Boolean by Preference(Constant.KEY_LOGIN, false) //取值or默认值 会调用getValue()
isLogin = true //赋值 会调用setValue()方法
三,总结
- 委托属性使我们的代码更加的简洁和优雅,可读性更高。
- 每次在by的时候都要new一个新的对象,这个在工具类中使用感觉不是很好,感觉不如单例好(个人猜想)