跳至主要內容

Android ViewModel源码梳理

PPLong大约 8 分钟学习AndroidAndroid Jetpack

ViewModel生命周期探究

前言

对ViewModel的使用一直处于会用但不清楚原理的阶段,目前有闲暇时间,探究一下ViewModel原理

前置条件

  • Android Compile SDK: 33
  • Dependency:
    • androidx.core:core-ktx:1.9.0
    • androidx.appcompat:appcompat:1.6.1
    • androidx.activity:activity-ktx:1.7.0

长篇源码警告

ViewModel Overview
ViewModel Overview

核心

ViewModelStoreOwner

持有ViewModelStore的对象,具有自己的生命周期. (Activity / Fragment 或其他自定义生命周期的View)

interface ViewModelStoreOwner {

    /**
     * The owned [ViewModelStore]
     */
    val viewModelStore: ViewModelStore
}

ViewModelStore

ViewModelStore持有ViewModel的最终管理集合(实质为LinkedHashMap),并以<String, ViewModel>的方式存储

open class ViewModelStore {

    private val map = mutableMapOf<String, ViewModel>()

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    fun put(key: String, viewModel: ViewModel) {
        val oldViewModel = map.put(key, viewModel)
        oldViewModel?.onCleared()
    }
  
  	// ...
}

ViewModelProvider

Jetpack中提供ViewModel的工具类(主要是创建ViewModel),通过Factory + Extras来进行基于不同功能的ViewModle的创建

生命周期

如何创建

重点理解ViewModel构造ViewModel时采用的链式构造模式,通过工厂模式,并内部使用继承/聚合的关系,从高级到低级工厂尝试构造符合当前ViewModel到实例对象。不满足上级条件则交由下一级构造,若不成功则继续交由下一级构造...

Factory-CreatingViewModel
Factory-CreatingViewModel

通过ViewModelProvider

在Activity中我们经常使用ViewModelProvier(this)[MViewModel::class.java]获取唯一的ViewModel实例,ViewModel是通过ViewModelProvider进行创建的,那么就从ViewModelProvider的构建开始, 假设要构造一个无参的ViewModel

public open class ViewModelProvider constructor(
    private val store: ViewModelStore,
    private val factory: Factory,
    private val defaultCreationExtras: CreationExtras = CreationExtras.Empty,
) {
    public constructor(
        owner: ViewModelStoreOwner
    ) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
}

即通过ViewModelProvier(this)[MViewModel::class.java]这种方式创建ViewModel时,ViewModelProvider初始化时使用了默认的Factory与Extras

看一下构造时传入的ViewModelStoreOwner与ViewModelStore。ViewModelStore相当于保存了多个ViewModel的一个存储结构,以KV键值对保存ViewModel,存储结构为LinkedHashMap

interface ViewModelStoreOwner {
    val viewModelStore: ViewModelStore
}

open class ViewModelStore {

    private val map = mutableMapOf<String, ViewModel>()

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    fun put(key: String, viewModel: ViewModel) {
        val oldViewModel = map.put(key, viewModel)
        oldViewModel?.onCleared()
    }

    /**
     * Returns the `ViewModel` mapped to the given `key` or null if none exists.
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    operator fun get(key: String): ViewModel? {
        return map[key]
    }

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    fun keys(): Set<String> {
        return HashSet(map.keys)
    }

    /**
     * Clears internal storage and notifies `ViewModel`s that they are no longer used.
     */
    fun clear() {
        for (vm in map.values) {
            vm.clear()
        }
        map.clear()
    }

那么Activity调用时传入this,那肯定Activity是实现了ViewModelStoreOwner接口的,最终在ComponentActivity中找到在getViewModelStore时复用或创建该ViewModelStore

// ComponentActivity
// 
private ViewModelStore mViewModelStore;
private ViewModelProvider.Factory mDefaultFactory;

@Override
public ViewModelStore getViewModelStore() {
    if (getApplication() == null) {
        throw new IllegalStateException();
    }
    ensureViewModelStore();
    return mViewModelStore;
}

// 确保mViewModelStore进行了初始化
void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
}

现在我们知道了如何创建ViewModelProvier了,那ViewModelProvier中get方法做了什么呢?

  • 通过默认的key前缀与Class的canonicalName组合成Key
  • 通过该key查找ViewModelStore中Map保存的ViewModel
    • 如果已经有实例了,那直接返回
    • 如果没有该实例,通过factory以及extra配置创建该ViewModel,调用的是factory中的create方法
// 注意, 该方法只能在主线程中调用
@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
    // canoncialName为返回一个类 易理解的 名称
    val canonicalName = modelClass.canonicalName
        ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
    return get("$DEFAULT_KEY:$canonicalName", modelClass)
}

@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
    val viewModel = store[key]
  	// 判断VMStore中存的vm是否是目标class的类型
    if (modelClass.isInstance(viewModel)) {
        // 调用Factory的回调
        (factory as? OnRequeryFactory)?.onRequery(viewModel)
        return viewModel as T
    } else {
        @Suppress("ControlFlowWithEmptyBody")
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    val extras = MutableCreationExtras(defaultCreationExtras)
    extras[VIEW_MODEL_KEY] = key
  	// 如果没有该实例,则通过fatcory创建
    return try {
        factory.create(modelClass, extras)
    } catch (e: AbstractMethodError) {
        factory.create(modelClass)
    }.also { store.put(key, it) }
}

这里factory是如何创造的呢?通过最开始初始化构建,我们知道是调用了内部构造默认factory的方法,这里逻辑稍微有点绕,但其实最后创建了SavedStateViewModelFactory

看一下构造ViewModelProvider时创建Factory的默认方法

public open class AndroidViewModelFactory
  private constructor(
      private val application: Application?,
      // parameter to avoid clash between constructors with nullable and non-nullable
      // Application
      @Suppress("UNUSED_PARAMETER") unused: Int,
  ) : NewInstanceFactory() {
    public companion object { 
      internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
          if (owner is HasDefaultViewModelProviderFactory)
              owner.defaultViewModelProviderFactory else instance

      @JvmStatic
      public fun getInstance(application: Application): AndroidViewModelFactory {
          if (sInstance == null) {
              sInstance = AndroidViewModelFactory(application)
          }
          return sInstance!!
      }
	 }
}

而ComponentActivity实现了接口HasDefaultViewModelProviderFactory

@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
    if (mDefaultFactory == null) {
        mDefaultFactory = new SavedStateViewModelFactory(
                getApplication(),
                this,
                getIntent() != null ? getIntent().getExtras() : null);
    }
    return mDefaultFactory;
}

class SavedStateViewModelFactory : ViewModelProvider.OnRequeryFactory, ViewModelProvider.Factory {
    private var application: Application? = null
    private val factory: ViewModelProvider.Factory
    private var defaultArgs: Bundle? = null
    private var lifecycle: Lifecycle? = null
    private var savedStateRegistry: SavedStateRegistry? = null
    constructor(application: Application?, owner: SavedStateRegistryOwner, defaultArgs: Bundle?) {
        savedStateRegistry = owner.savedStateRegistry
        lifecycle = owner.lifecycle
        this.defaultArgs = defaultArgs
        this.application = application
        factory = if (application != null) getInstance(application)
            else ViewModelProvider.AndroidViewModelFactory()
    }
  
    public fun getInstance(application: Application): AndroidViewModelFactory {
      if (sInstance == null) {
          sInstance = AndroidViewModelFactory(application)
      }
      return sInstance!!
    }
}

这里SavedStateViewModelFactory可以理解为持有Application对象的ViewModelFactory, 类似装饰者模式, SavedStateViewModelFactory维护了一个Factory, 实质为AndroidViewModelFactory, 而AndroidViewModelFactory为NewInstanceFactory的派生类,请记住以上的层级关系

以下开始探究factory.create调用的层级关系

// SavedStateViewModelFactory
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
    val key = extras[ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY]
        ?: throw IllegalStateException(
            "VIEW_MODEL_KEY must always be provided by ViewModelProvider"
        )

    return if (extras[SAVED_STATE_REGISTRY_OWNER_KEY] != null &&
        extras[VIEW_MODEL_STORE_OWNER_KEY] != null) {
        val application = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]
        val isAndroidViewModel = AndroidViewModel::class.java.isAssignableFrom(modelClass)
        // 判断是否是AndroidViewModel
      	// 并尝试根据是否需要SavedStateHandle来构造constructor(一般不需要)
        val constructor: Constructor<T>? = if (isAndroidViewModel && application != null) {
            findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE)
        } else {
            findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE)
        }
        // 如果不需要SavedStateHandle, 则通过内置factory构造ViewModel(一般为AndroidViewModelFactory)
        if (constructor == null) {
            return factory.create(modelClass, extras)
        }
        val viewModel = if (isAndroidViewModel && application != null) {
            newInstance(modelClass, constructor, application, extras.createSavedStateHandle())
        } else {
            newInstance(modelClass, constructor, extras.createSavedStateHandle())
        }
        viewModel
    } else {
        val viewModel = if (lifecycle != null) {
            create(key, modelClass)
        } else {
            throw IllegalStateException("SAVED_STATE_REGISTRY_OWNER_KEY and" +
                "VIEW_MODEL_STORE_OWNER_KEY must be provided in the creation extras to" +
                "successfully create a ViewModel.")
        }
        viewModel
    }
}


// AndroidViewModelFactory
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
    return if (application != null) {
        create(modelClass)
    } else {
        val application = extras[APPLICATION_KEY]
        if (application != null) {
            create(modelClass, application)
        } else {
            // For AndroidViewModels, CreationExtras must have an application set
            if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
                throw IllegalArgumentException(
                    "CreationExtras must have an application by `APPLICATION_KEY`"
                )
            }
            super.create(modelClass)
        }
    }
}

@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
    return if (application == null) {
        throw UnsupportedOperationException(
            "AndroidViewModelFactory constructed " +
                "with empty constructor works only with " +
                "create(modelClass: Class<T>, extras: CreationExtras)."
        )
    } else {
        create(modelClass, application)
    }
}

@Suppress("DocumentExceptions")
private fun <T : ViewModel> create(modelClass: Class<T>, app: Application): T {
  	// 判断是否是AndroidViewModel, 若是则根据Application创建ViewModel
    return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
        try {
            modelClass.getConstructor(Application::class.java).newInstance(app)
        } catch (e: NoSuchMethodException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        } catch (e: IllegalAccessException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        } catch (e: InstantiationException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        } catch (e: InvocationTargetException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        }
      // 一般ViewModel最终走这个逻辑
    } else super.create(modelClass)
}
// NewInstanceFactory
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
    return try {
      	// 使用ViewModel::class的无参构器构造该对象
        modelClass.getDeclaredConstructor().newInstance()
    } catch (e: NoSuchMethodException) {
        throw RuntimeException("Cannot create an instance of $modelClass", e)
    } catch (e: InstantiationException) {
        throw RuntimeException("Cannot create an instance of $modelClass", e)
    } catch (e: IllegalAccessException) {
        throw RuntimeException("Cannot create an instance of $modelClass", e)
    }
}

由上述分析,因为存在SavedStateViewModelFactory -> AndroidViewModelFactory -> NewInstanceFactory->newInstance这样的链关系,因此此时调用create方法时也存在一系列调用链的关系,其create方法根据extras信息做了一些判断,最后又调用到ViewModelProvier中AndroidViewModelFactory方法的create方法,做了一些判断,当不满足后又调用到NewInstanceFactory的create方法,最终通过反射构造了一个无参的ViewModel

至此,一个普通的无参ViewModel便构造完成了。

by viewModels()

经常使用的方式为委托方式,具体为

private val mViewModel: BaseViewModel by viewModels()

需要添加以下依赖"androidx.activity:activity-ktx:1.2.0"

Tips: 这里思考一下为什么使用reified关键字?

优点: 可以直接使用::class对象而不需要再传入表示class的klazz参数

// ActivityViewModelLazy.kt
@MainThread
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
    noinline extrasProducer: (() -> CreationExtras)? = null,
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
     		// 实际为ComponentActivity中的mDefaultFactory(SavedStateViewModelFactory)
        defaultViewModelProviderFactory
    }

    return ViewModelLazy(
        VM::class,
        { viewModelStore },
        factoryPromise,
        { extrasProducer?.invoke() ?: this.defaultViewModelCreationExtras }
    )
}

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

该委托方式为ComponentActivity及派生类才能调用, 实际返回的是基于Lazy接口的ViewModelLazy类

public class ViewModelLazy<VM : ViewModel> @JvmOverloads constructor(
    private val viewModelClass: KClass<VM>,
    private val storeProducer: () -> ViewModelStore,
    private val factoryProducer: () -> ViewModelProvider.Factory,
    private val extrasProducer: () -> CreationExtras = { CreationExtras.Empty }
) : Lazy<VM> {
    private var cached: VM? = null

  	// 延迟加载实际逻辑, get时才会初始化
    override val value: VM
        get() {
            val viewModel = cached
          	// 有cached就用cache
            return if (viewModel == null) {
                val factory = factoryProducer()
                val store = storeProducer()
              	// 实际还是使用ViewModelProvider构造ViewModel
                ViewModelProvider(
                    store,
                    factory,
                    extrasProducer()
                ).get(viewModelClass.java).also {
                    cached = it
                }
            } else {
                viewModel
            }
        }

    override fun isInitialized(): Boolean = cached != null
}

by activityViewModels()

可以看出,fragment中使用activityViewModels创建的ViewModel是依附于对应的Activity到viewModelStore,所以其生命周期与对应的Activity绑定

// FragmentViewModelLazy.kt
@MainThread
inline fun <reified VM : ViewModel> Fragment.activityViewModels(
    noinline factoryProducer: (() -> Factory)? = null
  // 关键代码
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore }, factoryProducer)

@MainThread
fun <VM : ViewModel> Fragment.createViewModelLazy(
    viewModelClass: KClass<VM>,
    storeProducer: () -> ViewModelStore,
    factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
        val application = activity?.application ?: throw IllegalStateException(
            "ViewModel can be accessed only when Fragment is attached"
        )
        AndroidViewModelFactory.getInstance(application)
    }
    return ViewModelLazy(viewModelClass, storeProducer, factoryPromise)
}

如何销毁

我们知道ViewModel在Activity 销毁时进行销毁,那具体是如何实现的呢?

ViewModel生命周期
ViewModel生命周期

在FragmentActivity时的onDestroy方法中,会通过Lifecycle机制进行通知(从之前探究Lifecycle机制的文章中有详细介绍)

@Override
protected void onDestroy() {
    super.onDestroy();
    mFragments.dispatchDestroy();
   	mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}

handleLifecycleEvent中会对lifecycle的状态进行改变并进行通知,最终进入到mLifecycleObserver.onStateChanged方法中

// ComponentActivity初始化时会添加lifecycle的observer进行监听
getLifecycle().addObserver(new LifecycleEventObserver() {
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            // Clear out the available context
            mContextAwareHelper.clearAvailableContext();
            // And clear the ViewModelStore
            if (!isChangingConfigurations()) {
                getViewModelStore().clear();
            }
        }
    }
});

这里的逻辑就很简单了,当Lifecycle为ON_DESTROY时,就对VMP进行清理,注意这里是清理该ViewModelStoreOwner下ViewModelStore中的所有的ViewModel!

参考网站🔗