ViewModel的原理解析

1.ViewModel

ViewModel作为Android JetPack里面的重要的一员,确实担任了一个十分重要的角色。也是实现MVVM架构的基础。所以会用并不能代表什么,而稍微把原理理清楚,你可以获得更多的知识(面试八股文)

2.功能

1.不会因为屏幕旋转等Actiity配置而导致销毁.
2.跟随生命周期
这里就不说明APi的使用了,网上文章太多了…
在这里插入图片描述

3.不会因为屏幕旋转等Actiity配置而导致销毁

这里只分析AndroidX
我们来看一下他为什么可以跟随生命周期把.
我们入口使我们的实例化过程

        viewModel = ViewModelProvider(this).get(DemoViewModel::class.java)

在ViewModelProvider.java中
可以看到它就是用的构造函数,而构造函数使用了getViewModel()函数

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }
 public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }

从getViewModel进入,会发现是一个接口,那它的实现类是在哪呢?
跟踪后发现是在CompontActivity.java中
可以发现,mViewModelStore就在这进来的,若为空则从一个叫做NonConfigurationInstances中获取,若里面没有东西则新建一个ViewModelStore.

  public ViewModelStore getViewModelStore() {
			//...
             if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

这里产生两个问题:
ViewStore是干嘛的?
NonConfigurationInstances又是干嘛的?

进入ViewStore类我们可以看到,它是存放ViewModel的一个存储类,里面用hashmap保存ViewModel. 这里留下这个clear()函数的伏笔

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();
    final ViewModel get(String key) {
        return mMap.get(key);
    }

  public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

NonConfigurationInstances的获取是由getLastNonConfigurationInstance()函数得到进入该函数
你会不知道写了什么东西.但是翻看官方文档得知,这个实例由onRetainNonConfigurationInstance()返回

 public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }

还是在ComponentActivity.java中找到该函数。
可以清楚的看到,nci偷偷的保存了viewModelStore.并且返回了该实例,这里返回的NonConfigurationInstances()类,就是getLast…返回的实例

  public final Object onRetainNonConfigurationInstance() {
        // Maintain backward compatibility.
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

所以我们也找到了保存的地方,在返回的地方我们也找到了~所以这就是在Activity配置转换的时候,viewModel不会被销毁的原因了.

4.跟随生命周期

来,官方文档经典生命周期.
在这里插入图片描述
可以看到,Viewmodel实在OnDestory后才onCleared的.那么我们的onCleared在那里调用以及如何保证的呢?.还记得我们上面留下的伏笔吗?
进入到该oncleared()函数,看他在哪里调用的.
仍然是ComponentActivity.java中
可以看到它直接用的是Lifecycle中的观察方式了.
So,Lifecycle也是JatPack的一员,它直接应用到这里了。
如果有不明白的可以先去了解一下Lifecycle.

public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
       
        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();
                    }
                }
            }
        });
    }

2022.5.20更新…

5.作用域可控

我们知道ViewModel其中的一个功能就是它的作用是根据自己的宿主决定的。如果是同一个ViewModel类,但是一个绑定Fragment,一个绑定的是Activity.那么两个的数据互不影响,也无法通信.
还记得我们上面说的.ViewStore嘛?ViewModel的创建就是初始化它和一个Factory.
在这里插入图片描述我们看NewInstanceFactory
在这里插入图片描述
使用了其反射构造方法去创建该类对象
我们再看它最终要执行的get()方法
在这里插入图片描述
在这里插入图片描述

最终拼接key。是否能从缓存中取出,不行则通过工厂创建并且存入缓存.所以,如果有作用域,那么Activity/Fragment必定会实现获得该实例的接口
我们回头看一下ComponentActivity可以看到它确实实现了该接口…
在这里插入图片描述
Fragment的话去查看FragmentManager.getViewModelStore()
所以他们内部都有去做实现去获取ViewModelStore的接口。又因为key,获取到了同一个ViewModel,以此来保证可控的作用域

Fragment → FragmentManager → FragmentManagerViewModel → mViewModelStores集合

所以:ViewModel的作用域可控 = 工厂模式 + 缓存集合(特定key规则)。

					又水了一篇,真开心~

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值