标题上写了三个话题, 它们是什么关系呢?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
{ -
- private var binding: VD? = null
-
- override fun getValue(thisRef: Activity, property: KProperty<*>): VD =
- binding ?: DataBindingUtil.setContentView
(thisRef, layoutRes) - .also { binding = it }
-
- }
而ActivityDataBindingDelegate实现了接口ReadOnlyProperty的getValue, getValue的函数签名是固定格式,而且我们知道约定要有operator修饰。
属性委托也有成对的get/set模式, 也就是接口ReadWriteProperty。
- public fun interface ReadOnlyProperty
{ - 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"
- }
它的意思是参数只会初始化一次,第一调用时会返回第一次初始化的值。
而且第一次使用是属性值初始化的时候,不是说在类的其他方法里第一次调用的时候。
- 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
, 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()