文章目录[x]
- 0.1:lazy
- 0.2:observable
- 0.3:vetoable
- 0.4:notNull
委托可以帮助你把任务委托给其他对象。Kotlin不仅支持用关键字实现委托,还提供内置的委托(lazy、observable、vetoable、notNull),本文将详细介绍Kotlin标准库中的这些内置委托。
lazy
lazy函数是一个属性委托,它可以帮助我们延迟初始化属性。
lazy(LazyThreadSafetyMode.SYNCHRONIZED){
//initializer
}
lazy函数有两个参数,分别是LazyThreadSafetyMode枚举和lambda函数。LazyThreadSafetyMode指定在不同线程之间初始化如何同步。lazy函数默认使用SYNCHRONIZED,用于确保只有一个线程可以初始化实例。
例如,线程安全的单例也可以像如下这样写:
class LocalDataManager private constructor(){
companion object{
@JvmStatic
val instance by lazy {
LocalDataManager()
}
}
}
查看SYNCHRONIZED模式的实现SynchronizedLazyImpl可以发现,在第一次访问其属性时,会在同步代码块中执行initializer方法来确保只生成一个实例:
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
observable
Delegates.observable()函数也是内置委托:
Delegates.observable(200){
property,oldValue,newValue->
}
这个函数基于观察者模式,在被观察者的值发生变化后,其第二个参数的onChange函数将会回掉:
private var mObserved by Delegates.observable(200){
property,oldValue,newValue->
Log.d(TAG,"property:"+property.name)
Log.d(TAG,"oldValue:"+oldValue)
Log.d(TAG,"newValue:"+newValue)
}
mObserved = 400
vetoable
Delegates.vetoable()函数返回读/写属性的属性委托,该属性委托在更改时调用指定的回调函数,从而允许回调否决修改。
private var mObserved by Delegates.vetoable(200){
property,oldValue,newValue->
newValue == 400
}
Log.d(TAG,"old:$mObserved")
mObserved = 300
Log.d(TAG,"new:$mObserved")
在运行上面的程序后,两次打印都为200,在只为400时,才能修改该属性。
notNull
Delegates.notNull<T>()返回具有非null值的读/写属性的属性委托,该值不是在对象构造期间初始化的,而是在以后的时间初始化的。 尝试在分配初始值之前读取属性会导致异常。
private var mValue by Delegates.notNull<Int>()
mValue = 100
Log.d(TAG,"value:$mValue")
只能在赋值之后才能访问该属性,它跟关键字lateinit的功能类似,但是更推荐使用lateinit关键字,因为使用notNull函数会创建额外的对象。