在fragment中使用
private val viewModel: xxxViewModel by viewModels()
就可以很方便的获取viewmodel的实例,看了一眼他的实现方式,好多高阶函数。这篇文章就来学习一下他的实现,顺便学习一下高阶函数的使用方式。
准备工作,app模块的build.gradle中引入如下扩展库
implementation "androidx.fragment:fragment-ktx:1.2.5"
首先看关键词 by
点进去是这么个鬼
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
这是获取 Lazy<T> 的值,这里说明ViewModel是通过懒加载的方式获取的实例,此viewModels()方法返回的是Lazy<VM>
然后点进去viewModels()看一眼
@MainThread
inline fun <reified VM : ViewModel> Fragment.viewModels(
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)
全是高阶函数,有意思了,一个个来分析
首先来看,viewModels 方法是Fragment的扩展函数,这就解释了为什么这个方法可以直接在Fragment中使用了
然后是ownerProducer 和 factoryProducer 这两个函数式入参。在kotlin中,函数是一等公民,可以作为参数,也可以作为返回值,作为参数的函数称之为高阶函数
先看一下ownerProducer高阶函数
ownerProducer: () -> ViewModelStoreOwner = { this }
这是一个没有入参,返回值为ViewModelStoreOwner的方法,这个方法的默认实现返回值为this-也就是Fragment本身
再看一下factoryProducer高阶函数
factoryProducer: (() -> Factory)? = null
这个函数就是一个没有入参,返回值为Factory的方法,而且此方法可为空,在这里就给赋值为null。看起来这个方法是有他没他照样过年的那种
在上面两个函数中还有一个修饰符 noinline
这里就引出了内联函数的概念,简单介绍一下
inline:通过内联(即函数内容直接插入到调用处)的方式来编译,用于方法
noinline:局部关掉这个优化,来摆脱不能把函数类型的参数当做对象使用的限制,用于参数
crossinline:局部加强内联优化,让内联函数里的函数类型的参数可以间接被调用,代价是不能在Lambda表达式里使用return,用于参数
最后看一眼viewModels扩展函数指向了createViewModelLazy函数,这个就有意思了,看一下实现
@MainThread
fun <VM : ViewModel> Fragment.createViewModelLazy(
viewModelClass: KClass<VM>,
storeProducer: () -> ViewModelStore,
factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(viewModelClass, storeProducer, factoryPromise)
}
这里的参数就是多了一个ViewModel的字节码而已,看factoryPromise
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
这个变量的值如果传入的参数factoryProducer为空的话,就调用Fragment中的defaultViewModelProviderFactory方法,即
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
requireActivity().getApplication(),
this,
getArguments());
}
return mDefaultFactory;
}
回到createViewModelLazy,此方法的最终返回值为 ViewModelLazy(viewModelClass, storeProducer, factoryPromise),看一眼实现,代码不多,就全粘了过来
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() = cached != null
}
看到这里,还记得by关键字么,就是调用其中的get方法
这里的核心方法为
ViewModelProvider(store, factory).get(viewModelClass.java).also {
cached = it
}
到这里,其创建过程和其中使用到的高阶函数就圆满结束了
网友评论