标题上写了三个话题, 它们是什么关系呢?by关键字用于属性委托和类委托,而Lazy是属性委托的一种优秀应用。
- 属性委托
属性的赋值来自定义好的委托类。使用更加简单,只要用关键字by指定委托类,就可以在运行时赋值了。属性委托也是约定的功能之一。
看下面的代码:目的是给MainActivity的ViewBinding根实例赋值。
class MainActivity {
override val viewDataBinding: ActivityMainBinding by ActivityDataBindingDelegate(R.layout.activity_main)
}
viewDataBinging的赋值来自ActivityDataBindingDelegate代理类getValue()函数的返回结果。
class ActivityDataBindingDelegate<out VD : ViewDataBinding>(@LayoutRes private val layoutRes: Int) :
ReadOnlyProperty<Activity, VD> {
private var binding: VD? = null
override fun getValue(thisRef: Activity, property: KProperty<*>): VD =
binding ?: DataBindingUtil.setContentView<VD>(thisRef, layoutRes)
.also { binding = it }
}
而ActivityDataBindingDelegate实现了接口ReadOnlyProperty的getValue, getValue的函数签名是固定格式,而且我们知道约定要有operator修饰。
属性委托也有成对的get/set模式, 也就是接口ReadWriteProperty。
public fun interface ReadOnlyProperty<in T, out V> {
public operator fun getValue(thisRef: T, property: KProperty<*>): V
}
public interface ReadWriteProperty<in T, V> : ReadOnlyProperty<T, V> {
public override operator fun getValue(thisRef: T, property: KProperty<*>): V
public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}
当然,不是说一定要实现这两个接口。属性委托限制的只是get/set的定义。
也可以这样:
class TestDelegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "alan"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("alan"+value)
}
}
fun main() {
var testDelegate by TestDelegate()
// 使用testDelegate ,这时候会去调用TestDelegate的getValue方法
println(testDelegate )
// 设置testDelegate 的值,这时候去会调用setValue方法
demoString = "gong"// 输出:"alan gong"
}
- Lazy懒加载
它的意思是参数只会初始化一次,第一调用时会返回第一次初始化的值。
而且第一次使用是属性值初始化的时候,不是说在类的其他方法里第一次调用的时候。
class TestLazy() {
private val name by lazy {
"alan"
}
}
lazy是个函数,返回实现Lazy接口的对象实例。默认是线程安全的SynchronizedLazyImpl。
按道理Lazy实现类SynchronizedLazyImpl,应该有属性委托的getValue()函数,但是看源码是没有的,但是在编译时生成的。不知道是为什么。但是有一个get()方法,作用是初始化值,以及处理多线程同步问题。
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
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
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
- 类委托
这个就是设计模式中的代理模式。只是比java更简便了。有一点要记住,代理方法都必须是事先定义好的接口。
class ByTest {
// 定义一个代理接口,和一个代理方法 show(), 这个接口必须定义。
interface Proxy{
fun show()
}
// 实现类实现 Proxy接口, 并实现 show 方法
open class ProxyImpl : Proxy{
override fun show() {
Log.e("ProxyImpl ::show()")
}
}
// 定义代理类实现 Proxy接口, 构造函数参数是一个 Proxy对象
// by 后跟 Proxy对象, 不需要再实现 show()
class NeedProxy(proxy: Proxy) : Proxy by proxy{
fun showOther() {
Log.e("NeedProxy::showOther()")
}
}
// main 方法
fun mainGo() {
val base = ProxyImpl ()
NeedProxy(base).show()
NeedProxy(base).showOther()
}
}
输出:
ProxyImpl::show()
NeedProxy::showOther()