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 fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
再点
public class ViewModelLazy<VM : ViewModel> (
private val viewModelClass: KClass<VM>,
private val storeProducer: () -> ViewModelStore,
private val factoryProducer: () -> ViewModelProvider.Factory
) : Lazy<VM> {
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<out T> {
public val value: T
public fun isInitialized(): Boolean
}
public fun <T> lazyOf(value: T): Lazy<T> = InitializedLazyImpl(value)
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
最后一行是关键!用扩展函数声明了 operator getValue 函数。 真相大白。
|