Android Jetpack 之 ViewModel 源码探究

6 阅读10分钟

Jetpack 系列文章都是在学习时候的笔记

写文章的思路是从想到什么问题,到解释这个问题来进行表述的.

不建议通篇阅读, 关心那个看对应的实现即可.

核心类定义:

ViewModelStoreOwner:

interface ViewModelOwner{
	val viewModelStore: ViewModelStore
}

ViewModelProvider: ViewModel 的提供商, 构造函数中需要提供 Factory 和 Extras

class ViewModelProvider{
	public constructor(owner: ViewModelStoreOwner){
		// defaultFactory 传 owner 是判断是会否是 HasDefaultViewModelProviderFactory, 
		// 取 Activity 携带 SaveStateViewModelFactroy
		// defaultCreationExtral 传 owner 是判断是会否是 HasDefaultViewModelProviderFactory, 
		// 取 Activity 携带 默认参数, 一般会有 application, 和宿主自身的引用.
		this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtral(owner))
	}
	public constructor(owner: ViewModelStoreOwner, factory: Factory){
		this(owner.viewModelStore, factory, defaultCreationExtral(owner))
	}
	public constructor(store: ViewModelStore, factory: Factory, extral: CreateExtras){}
}

Factory: ViewModel 的创建工厂, 常使用到的有 NewInstanceFactory(默认实现) AndroidViewModelFactory(AndroidViewModel 的创建工厂) InitializerViewModelFactory(带参数的构造器) SaveStateViewModelFactory

interface Factory{
	public fun <T: ViewModel> create(modelClass: Class<T>): T{}
	public fun <T: ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T{}
	companion object{
		// 带参数创建
		fun from(varrag initializers: ViewModelInitializer<*>): Factory = InitializerViewModelFactory(*initializers)
	}
}

// 定义 key
object IdKey: CreateExtras.Key<Int>
object NameKey: CreateExtras.key<String>
// 定义 ViewModel
class TestViewModel(val id: Int, val name: String): ViewModel()
// 创建 Factory
val factory = viewModelFactory{
	initializer{
		val id = this[IdKey]?:error("id error.")
		val name = this[NameKey]?:error("name error.")
		TestViewModel(id, name)
	}
}
// 创建 extras
val extras = MutableCreationExtras().apply{
   this[IdKey] = 1
   this[NameKey] = "Tom"
}
// 创建 viewModel
val viewModel: TestViewModel = factory.create(TestViewModel::class, extras)

需要搞清楚的问题:

1: ViewModel 的创建方式是什么?

ViewModelProvider(this)[xxx::class.java]

provider#get() → store 中取 → 取 Extras → 调用factory#create → 在 store 中存储

核心是通过两步(1): 创建 ViewModelProvider. (2) 调用 ViewModelProviderget 方法中调用了 factoryCreate以此来创建 ViewModel.

以上点中核心类有如下几个:

ViewModelProvider ViewModelStore ViewModelStoreOwner Factory

  • ViewModelProvider :有三个缺省的构造方法. 已经两个 get 函数,如果存在即返回, 如果不存在, 则调用 factory 进行创建.

    // 完整构造函数
    constructor(
        private val store: ViewModelStore,
        private val factory: Factory,
        private val defaultCreationExtras: CreationExtras = CreationExtras.Empty,
    )
      // 默认构造函数 -> 只有 ViewModelStoreOwner
      public constructor(
            owner: ViewModelStoreOwner
    	    ) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
      // 传入 ViewModelStoreOwner 加上 Factory 的构造函数
      public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
          owner.viewModelStore,
          factory,
          defaultCreationExtras(owner)
      )
      // 符号改写的 get 方法.
      public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
            val canonicalName = modelClass.canonicalName ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
            return get("$DEFAULT_KEY:$canonicalName", modelClass)
       }
      public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
          val viewModel = store[key]
          if (modelClass.isInstance(viewModel)) {
              (factory as? OnRequeryFactory)?.onRequery(viewModel!!)
              return viewModel as T
          } else { // 空实现.
              if (viewModel != null) {
              }
          }
          val extras = MutableCreationExtras(defaultCreationExtras)
          extras[VIEW_MODEL_KEY] = key // 塞入 key.
          return try {
              factory.create(modelClass, extras)
          } catch (e: AbstractMethodError) {
              factory.create(modelClass)
          }.also { store.put(key, it) }
      }
    
  • ViewModelStore :一个封建的 map. 封装的意义在于(1): 提供了 clear 方法, 方便所有的 ViewModel 的清空.(2): put 操作, 对于之前存在 viewModel 进行清空. clear 和 onCleared 分别是系统自己调用的和给外部调用的, clear 会调用都 onCleared.

    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()
        }
    
        @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)
        }
    
        fun clear() {
            for (vm in map.values) {
                vm.clear()
            }
            map.clear()
        }
    }
    
  • ViewModelStoreOwner: 提供了一个返回ViewModelStore的接口. 也就是说实现了 ViewModelStoreOwner 的都需要提供用来存储 ViewModel 的集合. 这样 ViewModelStoreOwner 都可以拿到对应属于自己的 ViewModel 的存储对象.

    interface ViewModelStoreOwner {
        val viewModelStore: ViewModelStore
    }
    
  • Factory: 提供了创建 ViewModel的方式, 核心方法在 Create 中. 在 ViewModelProvider中提供调用.主要的实现有: NewInstanceFactory(默认实现, 只创建不含 extra 的 ViewModel) AndroidViewModelFactory承担了大部分的创建任务.SavedStateViewModelFactory ComponentActivity 的默认使用,内部调用还是AndroidViewModelFactory, 提供了 Application 的绑定.

    public interface Factory {
            public fun <T : ViewModel> create(modelClass: Class<T>): T {
                throw UnsupportedOperationException("Factory.create(String) is unsupported.  This Factory requires `CreationExtras` to be passed into `create` method.")
            }
            public fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T = create(modelClass)
            companion object {
                @JvmStatic
                fun from(vararg initializers: ViewModelInitializer<*>): Factory = InitializerViewModelFactory(*initializers)
            }
      }
    
    // 默认实现
    public open class NewInstanceFactory : Factory {
        @Suppress("DocumentExceptions")
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return try {
                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)
            }
        }
    
        public companion object {
            private var sInstance: NewInstanceFactory? = null
    
            @JvmStatic
            public val instance: NewInstanceFactory
                @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
                get() {
                    if (sInstance == null) {
                        sInstance = NewInstanceFactory()
                    }
                    return sInstance!!
                }
    
            private object ViewModelKeyImpl : Key<String>
            @JvmField
            val VIEW_MODEL_KEY: Key<String> = ViewModelKeyImpl
        }
    }
    // 实现的 AndroidViewModel
    public open class AndroidViewModelFactory
        private constructor(
            private val application: Application?,
            @Suppress("UNUSED_PARAMETER") unused: Int,
        ) : NewInstanceFactory() {
    
            public constructor() : this(null, 0)
    
            public constructor(application: Application) : this(application, 0)
    
            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)
                    }
                }
            }
    
            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)
                }
            }
    
            private fun <T : ViewModel> create(modelClass: Class<T>, app: Application): T {
                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)
                    }
                } else super.create(modelClass)
            }
    
            public companion object {
                internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
                    if (owner is HasDefaultViewModelProviderFactory)
                        owner.defaultViewModelProviderFactory else instance
    
                internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"
    
                private var sInstance: AndroidViewModelFactory? = null
                @JvmStatic
                public fun getInstance(application: Application): AndroidViewModelFactory {
                    if (sInstance == null) {
                        sInstance = AndroidViewModelFactory(application)
                    }
                    return sInstance!!
                }
    
                private object ApplicationKeyImpl : Key<Application>
    
                @JvmField
                val APPLICATION_KEY: Key<Application> = ApplicationKeyImpl
            }
        }
        
        // ComponentActivity 中默认的 Factory
        class SavedStateViewModelFactory : ViewModelProvider.OnRequeryFactory, ViewModelProvider.Factory {
        private var application: Application? = null
        private val factory: ViewModelProvider.Factory // 持有一个AndroidViewModelFactory
        private var defaultArgs: Bundle? = null
        private var lifecycle: Lifecycle? = null
        private var savedStateRegistry: SavedStateRegistry? = null
    
        constructor() {
            factory = ViewModelProvider.AndroidViewModelFactory()
        }
        constructor(
            application: Application?,
            owner: SavedStateRegistryOwner
        ) : this(application, owner, 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()
        }
        
        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] // 拿到 defaultViewModelCreationExtras 中的 application
                val isAndroidViewModel = AndroidViewModel::class.java.isAssignableFrom(modelClass) // 判断需要创建的 ViewModel 是否是AndroidViewModel
                val constructor: Constructor<T>? = if (isAndroidViewModel && application != null) {
                    findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE)
                } else {
                    findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE)
                }
                // doesn't need SavedStateHandle
                if (constructor == null) {
                    return factory.create(modelClass, extras) // 直接通过 AndroidViewModel 来创建.
                }
                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
            }
        }
    }
    

2: ViewModel 和 Activity 如何实现的绑定? 在什么时候销毁?

ComponentActivity 实现了 ViewModelStoreOwner 接口. 提供了可以用来存储 ViewModel 的能力.

ViewModel 创建的时候就存在了 ActivityViewModelStore 中.

在收到 ActivityOnDestory 事件的时候就会销毁 ViewModelStore 中所有的 ViewModel.

3: Activity 恢复的时候 ViewModel 是否会恢复? 会恢复什么? SavedStateViewModelFactory 是怎么用的, 存了些什么恢复了些什么? 什么情况下恢复. viewModelStore 中存的 viewModel 既然之后 onDestroy 的时候才会被销毁, 那页面专向会onDestroy吗? 如果会是怎么恢复的, 如果不会,那什么情况下才会被销毁, 什么情况下 SavedStateRegister才能用上.?

!! 由 页面重新旋转导致的页面重绘是不会让ViewModelOwner 存储的 viewModel 清空,因为在 componentActivity 处理 viewModelStore 的清空的时候是有专门判断是否是从 changingConfiguration 来的.

用法:

class xxViewModle(private val application: Application, private val handle: SaveStatehandle): 
		AndroidViewModel(application){
		val query: LiveData<String> = handle.getLiveData("query", "")
		
		fun setQuery(value: String){
				handle["query"] = q
		}
		
		// 在首次调用 setQuery("123"), 进程异常恢复之后,哪能拿到 query 的监听回调.
}

(1): SavedStateHandle 的存(handle["query"])和取(handle.getLiveData("query", ""))是如何实现?

handle → SaveStateHandle set() 存入的 LiveData/Flow.

进程销毁的时候存savedStateProviderregular

初次有值 → SavedStateOwner 调用 SavedStateRegistry performRestore 存入到SavedStateRegistry 内部 restoredState 中, consumeRestoredStateForKey 就可以拿到. 在 SevedStateViewModelFactory create 就已经生成了, 然后通过构造函数的方式传入了 SavedStateHandle.

(2): 为什么可以给构造函数塞入 SaveStatehandle并生效的.

确定 ComponentActivity 使用的是 SavedStateViewModelFactory. SavedStateViewModelFactory 自己内部其实代理了 ApplicationFactory 的 Instance, 在调用他的 create 时候, 先通过 viewModel 的签名判断是否需要 SavedStateHandel 的构造函数, 如果不需要就按照之前的逻辑进行分, 使用 ApplicationFactory 或者 SingleInstanceFactory. 如果需要 SavedStateHandel 则通过 Extras 拿到 SavedStateHandel 对应的参数, LifeCycleOwner, SavedStateRegistryOwner. 这样就把 SavedStateHandle 传入进去了.

(3): 具有存储能力的 SavedStateViewModelFactory 是如何工作的, 哪些场景在会用到 SavedStateViewModelFactory

理论上具有数据恢复能力的位置, componentActivity/ Fragment, 都用到了 SavedStateViewModelFactory

主要是提供了 SaveStatehandle 构造函数,可以用来存储异常删除的数据. 具体的恢复和存入逻辑是由于 SavedStateRigistryOwner提供的. SaveStatehandle 主要实现了(1): 初始的时候拿到数据. (2) 提供了 SavedStateProvider 的存储接口, (3): 将内部数据变为 Flow/ LiveData 的能力.

4: ViewModel 如何实现自定义传参?

  • 核心是通过InitializerViewModelFactory实现,InitializerViewModelFactory 的 Create 函数, 会遍历自己的ViewModelInitializer构造函数, 来创建 ViewModel, 而 viewModelFactory 扩展函数, 的参数是一个 InitializerViewModelFactoryBuilder 的扩展函数, InitializerViewModelFactoryBuilder 中又提供了 addInitializer 的能力, addInitializer 的参数是 类名和创建 ViewModel 的initializer 函数, initializer 又是 CreationExtras 的扩展函数,

    ⇒ 最后就形成了这样的形式. 最后也就是自定义 factory , 自定义 extras, 来实现创建过程.

    val factory = viewModelFactory {
    	initializer { // CreationExtras 的扩展函数, 可以拿到 key.
    	  TestViewModel(this[key]) 
    	}
    }
    
    // 定义 key
    object IdKey: CreateExtras.Key<Int>
    object NameKey: CreateExtras.key<String>
    // 定义 ViewModel
    class TestViewModel(val id: Int, val name: String): ViewModel()
    // 创建 Factory
    val factory = viewModelFactory{
    	initializer{
    		val id = this[IdKey]?:error("id error.")
    		val name = this[NameKey]?:error("name error.")
    		TestViewModel(id, name)
    	}
    }
    // 创建 extras
    val extras = MutableCreationExtras().apply{
       this[IdKey] = 1
       this[NameKey] = "Tom"
    }
    // 创建 viewModel
    val viewModel: TestViewModel = factory.create(TestViewModel::class, extras)
    

5: ViewModel 和 AndroidViewModel 的区别?

两者是否具有 Application. ViewModel 是通过 NewInstanceFactory 来构造的. AndroidViewModel 是通过 AndroidViewModelFactory 来构造的.

6: Activity 的 ViewModel 和 Fragment 的 ViewModel 如何共享?是否可以共享?

ViewModel 存储的位置: ViewModelOwnerviewModelStore 中, 提供了 put/get/clean方法. 所以 ActivityFragmentviewModel 是否可以共用 取决于使用的是否是同一个 ViewModelOwnerviewModelStore

Activity → Fragment. Fragment 可以拿到 Activity 的引用, 判断是否是 ViewModelOwner, 如果是的话, 直接通过 构造 ViewModelProvider, 调用 Get 方法就可以拿到.

Fragment → Activity. 通过 FragmentManager 的 findById 的方式拿到 Fragment,然后通过和上面一样的方式来获取

7: Fragment 的 ViewModel 和 Activity ViewModel有和不同?

使用的 ViewModelOwner 不同 → ViewModelStore不同

  • (1) 为什么 ViewModelProvider 需要 ViewModelOwner 作为构造函数,内部只使用了 ViewModelStore

    a: 给了 ViewModelOwner 就可以方便的拿到 ViewModelStore

    b: 给了 ViewModelOwner 等于给了 Activity 的引用就可以通过 HasDefaultViewModelProviderFactory 借口拿到 ViewModelOwner 制定的 Factory/Extras, Activity/Fragment 都是使用这个逻辑来实现了 SavedStateViewModelFactory.

  • (2) ViewModeStore 还有什么特殊逻辑?

    ViewModeStore 只是一个包装的 map, 提供了 set/get/clean 的能力. 但是需要 activity/fragment 在 onDestroy 调用 clean 的时候都会判断是否因为因为配置修改导致的.

  • (3) ViewModel 自己有什么特殊逻辑?

    提供了 setTag 和 clean 的逻辑.

8: 常用的 ViewModel 之间的差异? 常用的 Factory 有哪些, 差异是什么?

常用的 ViewModel 只有两个 ViewModel/AndroidViewModel. AndroidViewModel 继承 ViewModel, 差异只是 AndroidViewModel 多了一个构造函数.

常用的 Factory 有: NewInstanceFactory/AndroidViewModelFactory/SavedStateViewModelFactory/InitializerViewModelFactory

  • (1) NewInstanceFactory

    用途: 异常情况下的兜底. 只能创建一个空的无参数的构造方法

    只实现了参数是类型名称的构造方法. 带 Extras 的都没有实现. 基本很少用.

  • (2) AndroidViewModelFactory

    用途: 用来创建一个 application 的 AndroidViewModel. 异常情况下再尝试调用父类创建无参的 ViewModel

    注意点: a: 两个 Crate 方法都有实现. b: application 有两个来源, 构造函数可以穿, 通过 Extras 也可以携带.都是通过反射的方式创建的.

  • (3) SavedStateViewModelFactory

    用途: ComponentActivity 和 Fragment 的默认 Factory. 实现数据的存储和恢复.

    注意点: (a): 如果使用无参数的构造函数, 默认用的就是 AndroidViewModelFactory

    (b): 内部会持有一个 factory → AndroidViewModelFactory, 来做具体的创建

    (c): 希望传入一个 SavedStateRegistryOwner, 从宿主拿到缓存的数据已经缓存的能力.

    (d): ViewModel 的构造函数支持一个额外的参数: SavedStateHandle, 来操作 SavedStateRegistryOwner 中拿到的数据, 已经保存的数据.

    (e): SavedStateHandle 提供了恢复的数据转成 LiveDate/StateFlow 的能力, 已经修改的包装.

  • (4) InitializerViewModelFactory

    用途: 提供自定义入参的 ViewModel 的实现.

    注意点: (a:)InitializerViewFactory中持有一组创建规则, class → CreationExtras.() ⇒ T, 使用符合规则的创建函数来创建 ViewModel.

    (b): 创建函数是 CreationExtras.的扩展函数,这样更方便取数.

9: CreationExtras.Key 比 Map<String, Any> 好在哪里?

(1) 基于泛型 → 类型可推导

object IdKey : CreationExtras.Key<Int> val id: Int = extras[IdKey] *// ✅ 编译期保证 Int*

val id = map["id"] as Int map 就做不到.

(2) 避免「字符串命名冲突」

map["id"] = 1 *// A 模块* map["id"] = "xxx" *// B 模块(无感覆盖)*

object UserIdKey : CreationExtras.Key<Int> object OrderIdKey : CreationExtras.Key<Long>

10: 存在哪些好的设计模式?

(1): 创建都通过 ViewModelOwner 来, 让 ViewModel 都和Owner 进行绑定. Owner 同时也是 LifecycleOwner, 这样方便和 Lifecycle 进行关联.

(2): 创建 HasDefaultViewModelProviderFactory接口. 这样就需要把类反复传输, 就可以使用 Owner 自己的 Factory 来实现定制功能.

(3): 结合 SavedStateRegistryOwner 来实现存储能力. 将存储能力够暴露给了 SavedStateHandle 类.

(4): SavedStateHandle 将数据转为 LiveData/Flow, 同时进行了转发, 让使用方可以完全忽略保存和获取的细节.