ViewModel源码分析(一)

246 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

前言

在 JetPack 组件中,ViewModel 主要用于封装与接口相关的数据。同样,ViewModel 具有生命周期感知能力。在Activity或Fragment onDetach销毁之前一直存在于内存中;尤其是屏幕旋转等系统配置变化后,ViewModel保存的界面数据依然存在。使用方式我们不用了解了,接下来让我们了解一下ViewModel的源码实现。

前言

在 JetPack 组件中,ViewModel 主要用于封装与接口相关的数据。同样,ViewModel 具有生命周期感知能力。在Activity或Fragment onDetach销毁之前一直存在于内存中;尤其是屏幕旋转等系统配置变化后,ViewModel保存的界面数据依然存在。使用方式我们不用了解了,接下来让我了解一下ViewModel的源码实现。

ViewModel的创建

viewmodels

我们从Fragment的viewModels语法糖进入源码的查看

@MainThread
public inline fun <reified VM : ViewModel> Fragment.viewModels(
    noinline ownerProducer: () -> ViewModelStoreOwner = { this },
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> = createViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryProducer)

这是一个内联函数,参数列表是:

  • ownerProducer:返回的是 ViewModelStoreOwner类型,默认是this,也就是当前调用函数的所有者ActivityFragment
  • factoryProducer:创建ViewModel的工厂,可以为空,也可以自己定义,实现ViewModelProvider.Factory这个接口即可。 可以看得到viewmodels调用了createViewModelLazy这个方法。

createViewModelLazy

@MainThread 
public fun <VM : ViewModel> Fragment.createViewModelLazy( 
    viewModelClass: KClass<VM>, 
    storeProducer: () -> ViewModelStore, 
    factoryProducer: (() -> Factory)? = null 
): Lazy<VM> { 
    val factoryPromise = factoryProducer ?: { 
        // 调用fragment的getDefaultViewModelProviderFactory方法
        defaultViewModelProviderFactory 
    } 
    return ViewModelLazy(viewModelClass, storeProducer, factoryPromise) 
}

// fragment
 public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        ...
     // 默认application是requireContext().getApplicationContext()
     Application application = null;
     Context appContext = requireContext().getApplicationContext();
     while (appContext instanceof ContextWrapper) {
         if (appContext instanceof Application) {
             application = (Application) appContext;
             break;
         }
         appContext = ((ContextWrapper) appContext).getBaseContext();
     }   
        
     mDefaultFactory = new SavedStateViewModelFactory(
         application,
         this,
         getArguments());
        
     return mDefaultFactory;
 }

// fragment
public SavedStateViewModelFactory(@Nullable Application application,
         @NonNull SavedStateRegistryOwner owner,
         @Nullable Bundle defaultArgs) {
     mSavedStateRegistry = owner.getSavedStateRegistry();
     mLifecycle = owner.getLifecycle();
     mDefaultArgs = defaultArgs;
     mApplication = application;
    // 上游application不为空
     mFactory = application != null
             ? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
             : ViewModelProvider.NewInstanceFactory.getInstance();
 }

如果传入的 factoryProducer 为空,则会创建一个默认的工厂,当application为空会返回NewInstanceFactory,不为空则返回AndroidViewModelFactory。这里根据源码我们知道application不为空,所以返回的是AndroidViewModelFactory

ViewModelLazy

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

首先,从缓存中获取 ViewModel。如果缓存中没有 ViewModel,则通过 ViewModelProvider + get 获取。这里我们主要看ViewModelProvider的get方法

ViewModelProvider


private val store: ViewModelStore,

@Suppress("UNCHECKED_CAST")
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
	val viewModel = store[key]
	// 不为空则返回viewmodel
	...
    return try {
        factory.create(modelClass, extras)
    } catch (e: AbstractMethodError) {
        factory.create(modelClass)
    }.also { 
    // 为空则创建不存到store中
    	store.put(key, it)
    }
}

这里我们可以看到viewModel通过调用factorycreate方法创建的,而factory是在Fragment调用createViewModelLazy方式后创建的,类型是AndroidViewModelFactory,它继承至NewInstanceFactory,实现了Factory的接口。

NewInstanceFactory

 @Override
  public T create() {
    try {
      return (T)myConstructor.newInstance(myArgs);
    }
    catch (Exception e) {
      LOG.error(e);
      return null;
    }
  }

这样就创建了一个ViewModel,并保存到store中,因此,在创建 ViewModel 时,viewModels 首先从缓存中获取它。如果不在缓存中,则从 store 中获取。如果它不在 store 中,则重新创建它。相当于三级缓存。