kotlin中用by关键字来实现委托,委托有类委托,属性委托。标题的 by viewModels 与 by activityViewModels 是用来实现属性委托的。
简单举个类委托的例子:
interface Animal {
fun do()
}
class Bird(val s: String) : Animal {
override fun do() { do(s) }
}
class Dog(a: Animal) : Animal by a
fun main() {
val bird = Bird("bird")
Dog(bird).do()
}
bird
可以看出,Dog里面没有定义do方法,却可以打印出bird,证明dog把方法委托给了传递进来的bird
重点来了,属性委托。
class Animal {
val name :String by AnimalDelegate()
}
class AnimalDelegate {
operator fun getValue(animal: Animal, property: KProperty<*>): String {
val s = "小猪"
println("setValue ${property.name} is ${s}")
return s
}
operator fun setValue(animal: Animal, property: KProperty<*>, s: String) {
println("setValue ${property.name} set to be ${s}")
}
}
上面的实现了对name的属性委托,注意,被委托的对象,也就是 by后面的,必须实现这两个方法!
operator fun getValue(animal: Animal, property: KProperty<*>): String {
val s = "小猪"
println("setValue ${property.name} is ${s}")
return s
}
operator fun setValue(animal: Animal, property: KProperty<*>, s: String) {
println("setValue ${property.name} set to be ${s}")
}
看方法签名,第一个参数为被委托对象所在的类,第二个参数为 KProperty
为什么会讲属性委托?因为 by lazy by viewModels by activityViewModes本质上都是属性委托。
lazy是函数,viewModels是函数,activityViewModels也是函数,他们返回了Delegate 对象。且这个对象必须要有 operator fun getValue operator fun setValue ,用val生命不需要 setValue.
点开viewModels源码,如下
public inline funComponentActivity.viewModels( noinline factoryProducer: (() -> Factory)? = null ): Lazy { val factoryPromise = factoryProducer ?: { defaultViewModelProviderFactory } return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise) }
再点
public class ViewModelLazy( private val viewModelClass: KClass , private val storeProducer: () -> ViewModelStore, private val factoryProducer: () -> ViewModelProvider.Factory ) : Lazy { private var cached: VM? = null override val value: VM get() { val viewModel = cached return if (viewModel == null) { val factory = factoryProducer() val store = storeProducer() ViewModelProvider(store, factory).get(viewModelClass.java).also { cached = it } } else { viewModel } } override fun isInitialized(): Boolean = cached != null }
再点
public interface Lazy{ public val value: T public fun isInitialized(): Boolean } public fun lazyOf(value: T): Lazy = InitializedLazyImpl(value) @kotlin.internal.InlineOnly public inline operator fun Lazy .getValue(thisRef: Any?, property: KProperty<*>): T = value
最后一行是关键!用扩展函数声明了 operator getValue 函数。
真相大白。



