public final String invoke() {
return name + lastname;
}
}));
让我们来观察 lazy() 的源码。由于 lazy()
函数默认使用 LazyThreadSafetyMode.SYNCHRONIZED
参数,因此它将返回一个 SynchronizedLazyImpl
类型的 Lazy 对象:
public actual fun lazy(initializer: () -> T): Lazy =
SynchronizedLazyImpl(initializer)
当属性代理第一次被访问时,SynchronizedLazyImpl
的 getValue()
函数就会被调用,这个函数将会在一个 synchronized
块中对属性进行初始化:
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
}
}
}
这样就能保证惰性对象会以线程安全的方式初始化,但同时也引入了由 synchronized
块带来的额外开销。
注意: 如果您确定资源会在单线程中被初始化,您可以向
lazy()
传入LazyThreadSafetyMode.NONE
,这样函数就不会在惰性初始化时使用synchronized
块。不过请记住,LazyThreadSafetyMode.NONE
不会改变惰性初始化的同步特性。由于惰性初始化是同步的,所以在第一次访问时仍会消耗与非惰性初始化过程相同的时间,这意味着那些初始化过程较为耗时的对象仍会在被访问时阻塞 UI 线程。
1val lazyValue: String by lazy(LazyThreadSafetyMode.NONE) {“lazy”}
惰性初始化可以帮助初始化昂贵资源,但对于诸如 String 一类的简单对象,由于 lazy()
函数需要生成 Lazy
和 KProperty
这样的额外对象,反而会增加整个过程的开销。
Observable
Delegates.observable() 是另一个 Kotlin 标准库中内建的代理。观察者模式是一种设计模式,在这一模式中,一个对象会维护一个它的从属者的列表,这些从属者即被称为观察者。对象会在它自己的状态改变时对观察者进行通知。这一模式十分契合多个对象需要在某个值发生改变时得到通知的情况,可以避免实现为从属对象周期调用和检查资源是否更新。
observable()
函数接收两个参数: 初始化值与一个当值发生改变时会被调用的监听处理器。observable()
会创建一个 ObservableProperty 对象,用于在每次 setter 被调用时执行您传给代理的 lambda 表达式。
class Person {
var address: String by Delegates.observable(“not entered yet!”) {
property, oldValue, newValue ->
// 执行更新操作
}
}
通过观察反编译后的 Person
类型,我们可以看到 Kotlin 编译器生成了一个继承 ObservableProperty 的类。这个类同时也实现了一个叫做 afterChange()
的函数,这个函数持有您传递给 observable 代理的 lambda 函数。
protected void afterChange(@NotNull KProperty property, Object oldValue, Object newValue) {
// 执行更新操作
}
afterChange()
函数由父 ObservableProperty
类的 setter 调用,这意味着每当调用者为 address
设置一个新的值,setter 就会自动调用 afterChange()
函数,结果就会使所有的监听器都会收到有关改变的通知。
class Person {
var address: String by Delegates.observable(“not entered yet!”) {
property, oldValue, newValue ->
// 执行更新操作
}
}
您还可以从反编译后的代码中看到 beforeChange()
函数的调用,observable 代理不会使用 beforeChange()
。但对于您接下来会看到的 vetoable()
,这一函数却是功能实现的基础。
vetoable
vetoable() 是一个内建代理,属性将否决权委托给它的值。与 observable()
代理类似,vetoable()
同样接受两个参数: 初始值与监听器,当任何调用者想要修改属性值时,监听器就会被调用。
var address: String by Delegates.vetoable("") {
property, oldValue, newValue ->
newValue.length > 14
}
如果 lambda 表达式返回 true,属性值就会被修改,反之则保持不变。在本例中,如果调用者尝试使用长度小于 15 个字符的字符串来更新地址的话,当前值就不会
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
发生改变。
观察反编译后的 Person
可以发现,Kotlin 新生成了一个继承 ObservableProperty
的类,该类中包含了我们传入 beforeChange()
函数的 lambda 表达式,setter 会在每次值被设置之前调用 lambda 表达式。
public final class Person s p e c i a l special specialinlined$vetoable$1 extends ObservableProperty {
protected boolean beforeChange(@NotNull KProperty property, Object oldValue, Object newValue) {
Intrinsics.checkParameterIsNotNull(property, “property”);
String newValue = (String)newValue;
String var10001 = (String)oldValue;
int var7 = false;
return newValue.length() > 14;
}
}
notNull
Kotlin 标准库中所提供的最后一个内建代理是 Delegates.notNull()。notNull()
允许一个属性可以延后一段时间初始化,与 lateinit 类似。由于 notNull()
会为每个属性创建额外的对象,所以大多数情况下推荐使用 lateinit
。不过,您可以将 notNull()
与原生类型一同使用,这点是 lateinit
所不支持的。
val fullname: String by Delegates.notNull()
notNull()
使用一种特殊类型的 ReadWriteProperty
: NotNullVar。
我们可以查看反编译后的代码,下面的例子中使用 notNull()
函数初始化了 fullname
属性:
this.fullname$delegate = Delegates.INSTANCE.notNull();
该函数返回了一个 NotNullVar
对象:
public fun notNull(): ReadWriteProperty<Any?, T> = NotNullVar()