美文网首页
高阶函数学习笔记-Fragment中viewModels扩展函数

高阶函数学习笔记-Fragment中viewModels扩展函数

作者: 紫鹰 | 来源:发表于2022-07-20 16:38 被阅读0次

    在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  
    }
    

    到这里,其创建过程和其中使用到的高阶函数就圆满结束了

    相关文章

      网友评论

          本文标题:高阶函数学习笔记-Fragment中viewModels扩展函数

          本文链接:https://www.haomeiwen.com/subject/fpxyirtx.html