Android ViewModel 作为 LifecycleOwner 落地的思考

3,059 阅读16分钟

Context

很早之前在项目中实现了一套从 ViewModel 获得生命周期 LifecycleOwner 的机制,最近引入到新项目中,也正好抽空整理分享一下以供其他同学参考,一起讨论一下 :P

先说一下背景,LifecycleOwner/Lifecycle 作为 Google Android Jetpack 的核心设计底座,不得不说真的是个非常牛逼和先进的 Idea. 从我个人理解来说,一切具有生命周期特征的对象理论上都可以抽象出 Lifecycle,于是有了下面的内容。

Why do this?

在之前的项目中,我负责的业务中基本上是比较严格地遵循 MVVM 的模式编写代码(即在 VM 中只负责接受用户事件并转换成业务意图分发给 biz model,同时维护业务场景数据和 UI 状态)。
而在实际开发的过程中会遇到这种场景:在 ViewModel 中调用某些业务 modelAPI 时需要提供 Lifecycle/LifecycleOwner.
(其实这个也算是比较常见的 case 了,比如调用某个业务 service 接口需要透传生命周期相关的参数)

由于个人原因我很讨厌在有更优选择的情况下增加代码耦合(像是给 ViewModel 增加方法注入来自 Fragment/ActivityLifecycleOwner 之类的操作)。例如下面这种写法:

class XXFragment {
    override fun onCreate(savedInstanceState: Bundle?) {
        …
        viewModel.bindLifecycleOwner(this)
    }
}

class XXViewModel {
    …
    override fun onCleared() {
        …
        this.hostLifecycleOwner = null
    }
    
    fun bindLifecycleOwner(lifecycleOwner: LifecycleOwner) {
        this.hostLifecycleOwner = lifecycleOwner
        lifecycleOwner.doOnDestroy { this.hostLifecycleOwner = null }
    }
}

为了满足业务场景需求,同时又不想增加这种很丑陋且没必要的函数,我就开动脑筋灵光一闪:ViewModel 这个东西,按照我对生命周期的理解其实也是一个具有生命周期的对象,为什么不能抽象成 LifecycleOwner 呢?

在经过了仔细思考之后,我确定这是一个完全可行的方向和做法。
开搞…

How to do it?

在确定了方向之后做法就比较明确了:我希望 ViewModel 可以作为 LifecycleOwner 相对单独存在,即可以从 ViewModel 实例直接获得生命周期相关的对象。

换句话说,其实需要做的事情就只有一个:当我有一个 ViewModel 的实例时,可以通过类似 viewModel.getLifecycleOwner() 或者 viewModel.getLifecycle() 的方式获得非空、可靠的生命周期对象。

(很简单对吧 :)

带生命周期的 ViewModel

首先 ViewModel 作为 Jetpack-lifecycle 套件提供给应用开发的基础组件,它只是一个普通的 Generic Java Class. 我们在业务开发中是不太能够对它作出修改的。

这里防杠一下,如果说通过 ASM/KCP 之类的方式修改编译产物当然是可以
怎么说,可以但没必要,而且有大炮打蚊子的嫌疑,阿巴阿巴…

so… 那么既然不能直接修改 ViewModel,那就换个思路,在参考了 Jetpack 套件的部分实现后,很快发现了两个比较快速的方法:

  1. 自定义 lazy 实现,完成生命周期的注入
  2. 自定义 ViewModelProvider.Factory 注入 (注 1)

感谢评论区 @zerdaket 指出的问题,为了防止对一些朋友可能产生的误导,在此补充说明
这里说的 “注入生命周期” ,指的是需要依赖 host(即 ViewModel 使用者)的生命周期做状态同步,比如 Activity/FragmentSTARTED/RESUMED 之类的状态;
在本文阐述的思路和方案中,ViewModel 对应的 LifecycleOwner 并非直接使用来自 host 的生命周期,而是单独维护一个自定义的 LifecycleOwner,跟 host LifecycleOwner 无关。

通过生产者注入生命周期

先看一下现在比较常见和广泛使用的官方推荐的创建 ViewModel 方法:

class XXActivity {

    val viewModel: XXViewModel by viewModels()

    override fun onCreate(…) {
        …
        viewModel.doSomething()
    }
}

Google 为了让我们使用 ViewModel 更便捷,不再推荐开发者使用 ViewModelProvider(this).get(XXViewModel::class.java) 这种稍显啰嗦的写法来创建了,取而代之的是通过 Activity/Fragment 的扩展方法来一键获取实例。

热知识:众所周知viewModels() 函数其实很简单,只是通过 inline 提供了范型信息、同时依赖 receiver 提供 ViewModelStoreOwnerfactory 来创建了一个 ViewModelLazy 对象并返回。跟手写 val viewModel: XXViewModel by lazy { … } 没有本质区别,只是把一些模版代码封在了 ViewModelLazy 内部更加便捷罢了。

那么接下来就很清楚了,参考 ViewModelLazy 我们自己实现一个 LifecycleViewModelLazy 就好了,只需要给我们创建的 ViewModel 自动注入一个 LifecycleOwner,ok 很简单

/**
 * Customized `lazy` delegate for [ViewModel] with lifecycle
 */
class LifecycleViewModelLazy<VM : ViewModel>(
    private val viewModelClass: KClass<VM>,
    private val storeProducer: () -> ViewModelStore,
    private val factoryProducer: () -> ViewModelProvider.Factory,
    private val lifecycleOwnerProducer: () -> LifecycleOwner,
) : 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
                    it.acquireLifecycleOwner().also { lifecycleOwner ->
                        lifecycleOwner.linkToHost(lifecycleOwnerProducer())
                        /* hook viewModel.viewModelScope, use lifecycle.coroutineScope instead
                         * lifecycle.coroutineScope 是 lifecycle-runtime-ktx 的 internal class LifecycleCoroutineScopeImpl, 会进行类型校验无法替换
                         */
                        it.hookViewModelScope(lifecycleOwner.lifecycle)
                    }
                }
            } else {
                viewModel
            }
        }

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

这里要解决的主要是在 lazy 内部创建 ViewModel 实例的时候,如何注入 LifecycleOwner 的问题。
实际上就是自定义了一个 ViewModelLifecycleOwner 类型实现 LifecycleOwner 接口,内部维护一个 LifecycleRegistry (可参考 ComponentActivity/Fragment):

  • 在自定义的 ViewModelLifecycleOwner 中需要通过对 host lifecycle 添加 observer 来观测上层的生命周期变化,及时同步更新自身的生命周期状态(via lifecycle::handleLifecycleEvent);
  • 以及在 Activity 中使用时需要注意一点,针对 Activity Lifecycle 销毁的情况处理 Activity::isChangingConfigurations() 重建的特殊 case (注 2).
    此时 Activity 对象销毁重建(会创建新的对象并流转生命周期)需要解除与上层生命周期的关联,并在新的 Activity 实例创建后重新建立关联。

此外,我们还需要做的就是把自定义的 LifecycleOwner 跟当前 ViewModel 实例关联起来,并提供一个 ViewModel 的扩展方法来取回相关联的 LifecycleOwner 即可。

注意:这里的自定义 LifecycleOwner 用于关联宿主(Activity/Fragment/Others)的生命周期,并不持有 hostLifecycleOwner(Activity/Fragment) 的引用

然后提供一个 Activity/Fragment 可使用的 lazy 函数快速使用:

@MainThread
inline fun <reified VM : ViewModel> ComponentActivity.lifecycleViewModels(
    noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: { defaultViewModelProviderFactory }
    return LifecycleViewModelLazy(VM::class, { viewModelStore }, factoryPromise, { this })
}

@MainThread
inline fun <reified VM : ViewModel> Fragment.lifecycleViewModels(
    noinline ownerProducer: () -> ViewModelStoreOwner = { this }, noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: { defaultViewModelProviderFactory }
    return LifecycleViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryPromise, { this })
}

通过 ViewModel 取得 LifecycleOwner

关于如何建立自定义 LifecycleOwnerViewModel 实例的 1-1 关联其实有很多办法,这里有一个我认为最简单的法子:直接复用 ViewModelgetTag(String) 函数和其内部的 mBagOfTags Map 容器。

ViewModel_tag_funcs

由于 ViewModel::getTag(String)<T> ViewModel::setTagIfAbsent(String, T) 的访问级别是 package 访问,所以只需要在相同包名下提供两个桥接方法即可顺畅的调用了:

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun <T> ViewModel.setTagIfAbsentX(key: String, value: T): T = this.setTagIfAbsent(key, value)

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun <T> ViewModel.getTagX(key: String): T? = this.getTag(key)

直接将创建实例时生成的 LifecycleOwner 存入 ViewModel::mBagOfTags 中,然后提供一个公开的扩展方法用于获取 LifecycleOwner

@Throws(IllegalStateException::class)
fun ViewModel.asLifecycleOwner(): LifecycleOwner = acquireLifecycleOwner().also {
    check(it.isLinked) { "Invalid: require `by lifecycleViewModels()`, and should invoke after instantiation complete." }
}

Enjoy

打完收工,实现过程并不复杂。从个人实际使用的感受上来说,雀食很香 :)

举个例子:
ViewModel 中需要调用业务 model 中的一个功能,而这个功能需要调用到其他业务 service 的方法,需要传递 LifecycleOwner, 这个时候就在 ViewModel 中直接提供无需依赖 Fragment 的传递,编码上更干净便捷。

// 某业务 Fragment
@AndroidEntryPoint
class XxxFragment : Fragment() {
    private val viewModel: XxxViewModel by lifecycleViewModel()
    …
}

// 业务 ViewModel
@HiltViewModel
class XxxViewModel @Inject constructor(private val bizModel: XxxBizModel) : ViewModel() {
    …
    fun doSometing() {
        // 业务 model 某些方法需要传递一个 LifecycleOwner, 直接从 ViewModel 获取无需任何依赖
        bizModel.someBizMethod(this.asLifecycleOwner(), …)
    }
}

// 业务 biz model
class XxxBizModel @Inject constructor() {
    …
    fun someBizMethod(lifecycleOwner: LifecycleOwner, …) {
        // 比如某些业务 service 的接口需要 LifecycleOwner, 就需要调用处传入,这算是一种很常见的场景
        getService<XxBizService>.someFunc(lifecycleOwner, …)
    }
}

争议和意见

虽然通过这种小的技巧实现了 ViewModel 的独立生命周期访问,但是之前在项目中给其他同学介绍了这种用法和思路的时候被 argue 了。

总的来说,关于 ViewModel 作为 LifecycleOwner 的用法主要有两个争议点:

  • 这种设计没有必要:ViewModel 正常来说在应用中就是作为 view-model 和胶水来使用的,官方也没有类似的实践和建议,不需要;
  • 属于强行设计,没有道理:ViewModel 没有生命周期的概念,强行认定为 LifecycleOwner 没有意义。

我的想法

对于不同的意见我们当然是认真倾听和思考了,当然作为开发者来说,保持开放的心态和学习态度非常重要。而且每个人有不同的思考和理解也很正常,这里再阐述一下我的个人理解,希望有其他的同学提供更多的角度来让大家一起思考。

对于我个人而言,这个 case 的出发点始于项目中实际应用的场景诉求。
但是回头再来思考整个设计,我依然坚持 ViewModel 有作为独立 LifecycleOwner 的合理性,理由有几点:

  1. 首先,从 ViewModel 的角色和作用来说,在一个完整的 MVVM 场景中作为 View 的协作者,它的实例生命周期理应是跟相关的 View (Activity/Fragment) 保持同步的,即随着 View 创建而创建,随着 View 的销毁而消亡。

  2. ViewModel 的代码实践中也能看出,ViewModel 实例存储于 ViewModelStore注 3: 这个基本上可以认为就是 Activity/Fragment),ViewModel::onCleared() 方法在所属的 host (Activity/Fragment) 销毁时被调用,即认为是消亡并释放资源。

  3. 论证 ViewModel 具备生命周期:
    a. 从上述两点来看,ViewModel 其实是具备生命周期特征的(这一点我觉得应该是没什么疑问的);
    b. 从另一个场外信息分析(从代码实现角度论证其独立性,仅作侧面参考),在分析了 Hilt (Dagger) 生成的 Components (Injector) 实现可以看到:
    ActivityCImpl_hierarchy ViewModelCImpl_hierarchy

    • Activity -> Fragment 的注入链是存在嵌套依赖关系的(即 FragmentCI 作为 ActivityCImpl 的内部类且构造器依赖 outer class 实例,可以注入来自 activity scope 的内容);
    • 而在 ViewModel 注入的实现中可以看到,ActivityCImplViewModelCImpl 同为 ActivityRetainedCImpl 内部类各自独立没有任何依赖和耦合关系,因此我认为从这个角度来看,ViewModel 在设计设计为度来看也是完全可以作为完整独立的组件来看待的。

结合上述三个角度来看:ViewModel 具有生命周期特征、ViewModel 有生命周期相关行为,且 ViewModel 完整独立。
所以我认为 ViewModel 是完全可以认定为具有独立生命周期的 LifecycleOwner 的。

补充说明

  • 注 1: 自定义 lazy 实现与 ViewModelProvider.Factory 可以结合在一起使用,将生命周期相关的注入逻辑沉入自定义的 Factory, 再改造一下 LifecycleViewModelLazy 内部的创建过程使用我们的自定义 Factory:

    open class LifecycleViewModelLazy<VM : ViewModel>(
        private val viewModelClass: KClass<VM>,
        private val storeProducer: () -> ViewModelStore,
        private val factoryProducer: () -> ViewModelProvider.Factory,
        private val lifecycleOwnerProducer: () -> LifecycleOwner,
    ) : Lazy<VM> {
        private var cached: VM? = null
    
        override val value: VM
            get() {
                val viewModel = cached
                return if (viewModel == null) {
                    val factory = factoryProducer()
                    val realFactory = if (factory is LifecycleViewModelFactory) factory else LifecycleViewModelFactory(factory, lifecycleOwnerProducer)
                    ViewModelProvider(storeProducer(), realFactory).get(viewModelClass.java).also { cached = it }
                } else {
                    viewModel
                }
            }
    
        final override fun isInitialized(): Boolean = cached != null
    }
    

    这样修改之后,在业务侧使用就不再限制需要使用特定的 lazy 函数了,可以通过重写 host getDefaultViewModelProviderFactory() 方法来保证创建的 ViewModel 是符合了预期的

  • 注 2: Activity 场景区别于在 Fragment 中使用 ViewModel,存在 Activity 销毁重建的情况,会出现 ViewModel 生命周期长于当前 Activity 实例的周期,而重建的 Activity 则是一个新的对象(即 Activity LifecycleOwner

    class TestActivity : AppCompatActivity() {
        private val viewModel: TestLifecycleViewModel by lifecycleViewModels()
        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            testLifecycle()
        }
        
        override fun toString(): String = "${javaClass.simpleName}{${Integer.toHexString(System.identityHashCode(this))}}"
    
        private fun testLifecycle() {
            viewModel // obtain viewModel
            this.lifecycle.addObserver(TestLifecycleObserver { event ->
                TAG logDIfLocalTest { "[$event] from Activity: $this" }
            })
            supportFragmentManager.also { fm ->
                fm.findFragmentByTag("fragment_test_lifecycle") ?: fm.commit { add(TestLifecycleFragment(), "fragment_test_lifecycle") }
            }
        }
        
        // test viewmodel
        class TestLifecycleViewModel : ViewModel(), ILifecycleLike {
            override fun onCreate() {
                asLifecycleOwner().lifecycle.addObserver(TestLifecycleObserver { event ->
                    TAG logDIfLocalTest { "[$event] from ViewModel: $this" }
                })
            }
    
            override fun toString(): String = "${javaClass.simpleName}{${Integer.toHexString(System.identityHashCode(this))}}"
        }
    
        // test fragment
        class TestLifecycleFragment : Fragment() {
            init {
                lifecycle.addObserver(TestLifecycleObserver { event ->
                    TAG logDIfLocalTest { "[$event] from Fragment: $this" }
                })
            }
        }
    }
    

    打印 log 如下:

    # 打开 Activity
    13:51:15.654  4348-4415  TestActivity      com.sample  D  [ON_CREATE] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:15.654  4348-4415  TestActivity      com.sample  D  [ON_CREATE] from Activity: TestActivity{b15b888}
    13:51:15.660  4348-4415  TestActivity      com.sample  D  [ON_CREATE] from Fragment: TestLifecycleFragment{3980406} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:15.661  4348-4415  TestActivity      com.sample  D  [ON_START] from Fragment: TestLifecycleFragment{3980406} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:15.671  4348-4415  TestActivity      com.sample  D  [ON_START] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:15.671  4348-4415  TestActivity      com.sample  D  [ON_START] from Activity: TestActivity{b15b888}
    13:51:15.671  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from Fragment: TestLifecycleFragment{3980406} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:15.671  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:15.671  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from Activity: TestActivity{b15b888}
    
    # 第一次翻转手机切换横屏
    13:51:24.024  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from Activity: TestActivity{b15b888}
    13:51:24.024  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:24.031  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from Fragment: TestLifecycleFragment{3980406} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:24.031  4348-4415  TestActivity      com.sample  D  [ON_STOP] from Activity: TestActivity{b15b888}
    13:51:24.031  4348-4415  TestActivity      com.sample  D  [ON_STOP] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:24.333  4348-4415  TestActivity      com.sample  D  [ON_STOP] from Fragment: TestLifecycleFragment{3980406} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:24.333  4348-4415  TestActivity      com.sample  D  [ON_DESTROY] from Activity: TestActivity{b15b888}
    13:51:24.353  4348-4415  TestActivity      com.sample  D  [ON_DESTROY] from Fragment: TestLifecycleFragment{3980406} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:24.402  4348-4415  TestActivity      com.sample  D  [ON_CREATE] from Fragment: TestLifecycleFragment{bdd7ffd} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:24.660  4348-4415  TestActivity      com.sample  D  [ON_CREATE] from Activity: TestActivity{3556353}
    13:51:24.675  4348-4415  TestActivity      com.sample  D  [ON_START] from Fragment: TestLifecycleFragment{bdd7ffd} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:24.675  4348-4415  TestActivity      com.sample  D  [ON_START] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:24.675  4348-4415  TestActivity      com.sample  D  [ON_START] from Activity: TestActivity{3556353}
    13:51:24.692  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from Fragment: TestLifecycleFragment{bdd7ffd} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:24.695  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:24.695  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from Activity: TestActivity{3556353}
    
    # 第二次翻转切换竖屏
    13:51:32.888  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from Activity: TestActivity{3556353}
    13:51:32.888  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:32.896  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from Fragment: TestLifecycleFragment{bdd7ffd} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:32.899  4348-4415  TestActivity      com.sample  D  [ON_STOP] from Activity: TestActivity{3556353}
    13:51:32.900  4348-4415  TestActivity      com.sample  D  [ON_STOP] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:32.906  4348-4415  TestActivity      com.sample  D  [ON_STOP] from Fragment: TestLifecycleFragment{bdd7ffd} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:32.908  4348-4415  TestActivity      com.sample  D  [ON_DESTROY] from Activity: TestActivity{3556353}
    13:51:32.910  4348-4415  TestActivity      com.sample  D  [ON_DESTROY] from Fragment: TestLifecycleFragment{bdd7ffd} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:33.011  4348-4415  TestActivity      com.sample  D  [ON_CREATE] from Fragment: TestLifecycleFragment{33dc95a} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:33.244  4348-4415  TestActivity      com.sample  D  [ON_CREATE] from Activity: TestActivity{cfba938}
    13:51:33.255  4348-4415  TestActivity      com.sample  D  [ON_START] from Fragment: TestLifecycleFragment{33dc95a} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:33.255  4348-4415  TestActivity      com.sample  D  [ON_START] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:33.255  4348-4415  TestActivity      com.sample  D  [ON_START] from Activity: TestActivity{cfba938}
    13:51:33.272  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from Fragment: TestLifecycleFragment{33dc95a} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:33.273  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:33.273  4348-4415  TestActivity      com.sample  D  [ON_RESUME] from Activity: TestActivity{cfba938}
    
    # 返回键关闭 Activity
    13:51:41.114  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from Activity: TestActivity{cfba938}
    13:51:41.114  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:41.119  4348-4415  TestActivity      com.sample  D  [ON_PAUSE] from Fragment: TestLifecycleFragment{33dc95a} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:41.682  4348-4415  TestActivity      com.sample  D  [ON_STOP] from Activity: TestActivity{cfba938}
    13:51:41.682  4348-4415  TestActivity      com.sample  D  [ON_STOP] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:41.686  4348-4415  TestActivity      com.sample  D  [ON_STOP] from Fragment: TestLifecycleFragment{33dc95a} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    13:51:41.691  4348-4415  TestActivity      com.sample  D  [ON_DESTROY] from Activity: TestActivity{cfba938}
    13:51:41.691  4348-4415  TestActivity      com.sample  D  [ON_DESTROY] from ViewModel: TestLifecycleViewModel{44280cf}
    13:51:41.694  4348-4415  TestActivity      com.sample  D  [ON_DESTROY] from Fragment: TestLifecycleFragment{33dc95a} (1467f9a9-5c83-4384-b4bf-20f6eb1cefaf tag=fragment_test_lifecycle)
    
    
  • 注 3: 对于 ViewModel 来说不论在 Activity 还是 Fragment 中使用,其存储与状态(如 ViewModel::onCleared)仅依赖 ViewModelStoreActivty/Fragment 则是通过实现 ViewModelStoreOwner 接口并提供一个 ViewModelStore 实例来管理 ViewModel 实例。
    理解了这一点那么对于 ViewModel 的使用就不限于 Activity/Fragment 了,任意业务组件其实都可以通过同样的方式来管理自己的 ViewModel 和依赖注入达到更彻底的解耦。比如目前尚在草稿阶段的某统一组件抽象方案(此处不展开)