一种跨 Activity 的 ViewModel 实现

背景

阅读该文章之前,我们需要详细了解 ViewModel 的实现原理。类似的文章非常的多,这里不在赘述。

在工作中,我们可能会遇到需要跨 Activity 共享 ViewModel 的场景,比如合集场景的内外流同步。当然了,我们完全可以使用 Fragment 来实现内外流同步这个功能,但由于历史原因,很多老 app 的内流是由 Activity 实现的,改造成 Fragment 已经完全不现实。

我们了解,ViewModel 在设计之时是没有考虑在不同 Activity之间共享的。我们需要使用一些特殊的方法来实现。查询网上大家的实现,发现都各有缺点。如

  1. https://blog.csdn.net/m0_59162559/article/details/138921230 该文章的思路是对的,但它放到了package androidx.lifecycle包下,略显奇怪,或者需要反射去调用store.put 函数。而且没有考虑过内流跳内流场景。(ActivityA->ActivityB->ActivityB)。缺点明显。
  2. https://www.sunofbeach.net/a/1643607587099435009 粗暴的共享 activity 的 viewModelStore,影响面太大。

我们需要实现一个跨 Activity 的ViewModel方案,并没有上述问题。

实现方法

ViewModelStore 是 ViewModel 的容器,是 Acitivty、Fragment 等组件持有 ViewModel 的方式。Activity、Fragment 通过实现 ViewModelStoreOwner 接口,向外界提供自己持有的 ViewModel;在生命周期走到 onDestory 的时候,清空 ViewModelStore,销毁所有数据。

考虑将 ViewModel 的生命周期延长到多个 Activity 生命周期的并集,自然而然的想法是:将同一个 ViewModel 的实例添加到两个 Activity 的 ViewModelStore 中,但是 ViewModelStore 不支持使用者手动调用其put(key: String, viewModel: ViewModel)方法,而且为了更方便的共享多个 ViewModel,我们考虑共享一个特殊的 ViewModelStore,用来承载所有需要共享的 ViewModel。

ACViewModelContainer

该类是一个普通的ViewModel,其内部承载了一个 ViewModelStore,该 ViewModelStore 用与Activity 跳转时候的共享。

class ACViewModelContainer @JvmOverloads constructor(
    application: Application,
    viewModelStore: ViewModelStore? = null
): AndroidViewModel(application){
    companion object {
       const val UNIVERSAL_SHARE_KEY = "UNIVERSAL_SHARE_KEY"
        private val refCounter = HashMap()
    }
    // 问题的关键在于,我们如何将想要共享的 viewModel 传递到这个 shareViewModelStore 中
    // 可以知道,在 get 的时候,viewModelProvider 会将创建好的 viewModel 传递到
    // viewModelStore中,所以,我们需要使用自己的 viewModelProvider 去控制这种行为。
    val shareViewModelStore = viewModelStore?: ViewModelStore()

    init {
        shareViewModelStore.let {
            refCounter[it] = (refCounter[it]?:0) + 1
        }
    }

    override fun onCleared() {
        super.onCleared()
        shareViewModelStore.let {
            if (!refCounter.containsKey(it) || (refCounter[it]?:0) <= 1) {
                shareViewModelStore.clear()
                refCounter.remove(shareViewModelStore)
            } else {
                refCounte

你可能感兴趣的:(安卓,ViewModel)