MVVM架构中,会用到ViewModel类,那么这个类原理是什么呢?有什么好处呢?

第一部分:源码文档解析

/*** ViewModel is a class that is responsible for preparing and managing the data for* an {@link android.app.Activity Activity} or a {@link androidx.fragment.app.Fragment Fragment}.//viewmodel类是用来在activity或fragment中获取和处理数据的类* It also handles the communication of the Activity / Fragment with the rest of the application//他也可以用来处理activity或fragment和应用其他模块的通信* (e.g. calling the business logic classes).* <p>* A ViewModel is always created in association with a scope (a fragment or an activity) and will* be retained as long as the scope is alive. E.g. if it is an Activity, until it is* finished.* <p>//viewmodel随着宿主的创建而创建,而且只要宿主还在他就会活着* In other words, this means that a ViewModel will not be destroyed if its owner is destroyed for a* configuration change (e.g. rotation). The new owner instance just re-connects to the existing model.* <p>//也就是说,这也就是如果宿主死了他不会跟着死的,例如activity的配置更改后重新创建,但是他还是原来的。* The purpose of the ViewModel is to acquire and keep the information that is necessary for an* Activity or a Fragment. The Activity or the Fragment should be able to observe changes in the* ViewModel. ViewModels usually expose this information via {@link LiveData} or Android Data* Binding. You can also use any observability construct from you favorite framework.* <p>//设计viewmodel的目的是获得和保持activity或fragment中的信息。宿主fragment/activity也应该观察viewmodel中数据的改变。viewmodel通常配合着databinding使用,你也可以使用其他具有观察特性的控件一起使用。* ViewModel's only responsibility is to manage the data for the UI. It <b>should never</b> access* your view hierarchy or hold a reference back to the Activity or the Fragment.* <p>//viewmodel仅仅用来管理更新UI的数据,而不应该持有view或者宿主的引用。* Typical usage from an Activity standpoint would be:* <pre>//使用示例如下:* public class UserActivity extends Activity {**     {@literal @}Override*     protected void onCreate(Bundle savedInstanceState) {*         super.onCreate(savedInstanceState);*         setContentView(R.layout.user_activity_layout);*         final UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);*         viewModel.getUser().observe(this, new Observer&lt;User&gt;() {*             {@literal @}Override*             public void onChanged(@Nullable User data) {*                 // update ui.*             }*         });*         findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {*             {@literal @}Override*             public void onClick(View v) {*                  viewModel.doAction();*             }*         });*     }* }* </pre>** ViewModel would be:* <pre>* public class UserModel extends ViewModel {*     private final MutableLiveData&lt;User&gt; userLiveData = new MutableLiveData&lt;&gt;();**     public LiveData&lt;User&gt; getUser() {*         return userLiveData;*     }**     public UserModel() {*         // trigger user load.*     }**     void doAction() {*         // depending on the action, do necessary business logic calls and update the*         // userLiveData.*     }* }* </pre>** <p>* ViewModels can also be used as a communication layer between different Fragments of an Activity.//viewmodel也可以用来用在同一个activity中不同fragment之间数据交换* Each Fragment can acquire the ViewModel using the same key via their Activity. This allows* communication between Fragments in a de-coupled fashion such that they never need to talk to* the other Fragment directly.* <pre>//每一个fragment可以通过同一个key获取到同一个viewmodel,这就实现了fragment之间的数据交换,而不是fragment之间进行数据交换。例如:* public class MyFragment extends Fragment {*     public void onStart() {*         UserModel userModel = new ViewModelProvider(requireActivity()).get(UserModel.class);*     }* }* </pre>* </>*/

通过官方文档我可以获取如下信息:

1.viewmodel的生命周期不随着宿主的死亡而死亡

2.viewmodel 主要是用来进行数据的传递更新UI,而不允许持有宿主的引用

3.viewmodel 应该配合着具有观察者模式的类一起使用,例如MutableLiveData

4.使用示例

5.viewmodel还可以作为同一个activity中不同fragment之间数据的传递,以及示例

第二部分:源码解析(上面示例用代码)

1.获取viewmodel

UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
/*** Creates {@code ViewModelProvider}. This will create {@code ViewModels}* and retain them in a store of the given {@code ViewModelStoreOwner}.* <p>* This method will use the* {@link HasDefaultViewModelProviderFactory#getDefaultViewModelProviderFactory() default factory}* if the owner implements {@link HasDefaultViewModelProviderFactory}. Otherwise, a* {@link NewInstanceFactory} will be used.*///参数二有删减,默认就是这个参数public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {this(owner.getViewModelStore(), NewInstanceFactory.getInstance());}

先看new ViewModelProvider(this):

参数为this(例如activity /fragment),那么是任何类都可以吗?不是,这个构造器的参数为ViewModelStoreOwner,这是个接口

public interface ViewModelStoreOwner {/*** Returns owned {@link ViewModelStore}** @return a {@code ViewModelStore}*/@NonNullViewModelStore getViewModelStore();
}

我们看看他的子类有哪些:

所以我们传入fragmentactivity可以,也就是如果不是这几个类,那么我们要实现这个接口才可以,我们可以看看ViewModelStore这个类是什么:

public class ViewModelStore {private final HashMap<String, ViewModel> mMap = new HashMap<>();final void put(String key, ViewModel viewModel) {ViewModel oldViewModel = mMap.put(key, viewModel);if (oldViewModel != null) {oldViewModel.onCleared();}}final ViewModel get(String key) {return mMap.get(key);}Set<String> keys() {return new HashSet<>(mMap.keySet());}/***  Clears internal storage and notifies ViewModels that they are no longer used.*/public final void clear() {for (ViewModel vm : mMap.values()) {vm.clear();}mMap.clear();}
}

核心代码,hashmap保存viewmodel的。

第二个参数NewInstanceFactory.getInstance()

public static class NewInstanceFactory implements Factory {private static NewInstanceFactory sInstance;@NonNullstatic NewInstanceFactory getInstance() {if (sInstance == null) {sInstance = new NewInstanceFactory();}return sInstance;}@SuppressWarnings("ClassNewInstance")@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {return modelClass.newInstance();}}

单例模式,就一个create方法,反射创建对象。

再次回顾一下两个重要点:

第一:一个hashmap保存viewmodel

第二:一个是创建viewmodel的

下面来看new ViewModelProvider(this).get(UserModel.class); get方法:

    @NonNull@MainThreadpublic <T extends ViewModel> T get(@NonNull Class<T> modelClass) {//获取全类名String canonicalName = modelClass.getCanonicalName();return get(DEFAULT_KEY + ":" + canonicalName, modelClass);}public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {//hashmap中获取ViewModel viewModel = mViewModelStore.get(key);//获取到了,说明以前创建过,则返回if (modelClass.isInstance(viewModel)) {return (T) viewModel;} //没获取到,则创建,通过上面分析的反射创建viewModel = mFactory.create(modelClass);//将创建的对象保存起来mViewModelStore.put(key, viewModel);return (T) viewModel;}

通过全类名在hashmap中查找,如果有则直接返回,没有则创建新的,并保存起来。所以说,我们多次调用get方法获取或者在同一个activity中不同fragment中使用new ViewModelProvider(getActivity()).get(UserModel.class) 都是获取到的同一个viewmodel。但是文档里说当activity的配置信息发生改变,activity重新创建的时候,viewmodel是不会重新创建的,可是我们看到的却是 mViewModelStore 是activity的一个属性,也就是说activity销毁的时候,他也应该被回收了,那应该随着新的activity的创建而创建新的viewmodel吧,文档写的貌似不对啊?其实文档写的没错,我们可以去activity里看看:

//activity配置发生改变是调用这个方法
public final Object onRetainNonConfigurationInstance() {NonConfigurationInstances nci = new NonConfigurationInstances();nci.custom = custom;nci.viewModelStore = viewModelStore;return nci;}

我们可以看到,当activity配置发生改变时,会将viewModelStore保存起来,当页面重新创建后再次获取实例时,会调用:

    @NonNull@Overridepublic ViewModelStore getViewModelStore() {ensureViewModelStore();return mViewModelStore;}@SuppressWarnings("WeakerAccess") /* synthetic access */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();}}}

会先在配置改变保存的数据里恢复数据,没有则再去创建。

后续viewmodel配合LiveData一起使用,我们后续再分析。这里就分析viewmodel的源码。

ViewModel 源码解析相关推荐

  1. Android JetPack ViewModel 源码解析

    是什么? ViewModel 用来存储页面相关的数据,当页面销毁的时候,存储数据也会清楚.但是当页面发生旋转的时候,并不会清楚数据. 怎么用? UserViewModel userViewModel ...

  2. 5. Jetpack源码解析---ViewModel基本使用及源码解析

    截止到目前为止,JetpackNote源码分析的文章已经有四篇文章了,这一系列的文章我的初衷是想仔细研究一下Jetpack,最终使用Jetpack组件写一个Demo,上一篇已经分析了LiveData, ...

  3. LiveData 源码解析(2.4.1 版本)

    文章目录 1.LiveData 简介 2.LiveData 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 LiveData 简单使用 2.2.2 LiveData 扩展 2.2 ...

  4. Lifecycle 源码解析(2.4.1 版本)

    文章目录 1.Lifecycle 简介 2.Lifecycle 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 Lifecycle 简单使用 2.2.2 普通 Activity ...

  5. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

  6. 谷歌BERT预训练源码解析(三):训练过程

    目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...

  7. 谷歌BERT预训练源码解析(一):训练数据生成

    目录 预训练源码结构简介 输入输出 源码解析 参数 主函数 创建训练实例 下一句预测&实例生成 随机遮蔽 输出 结果一览 预训练源码结构简介 关于BERT,简单来说,它是一个基于Transfo ...

  8. Gin源码解析和例子——中间件(middleware)

    在<Gin源码解析和例子--路由>一文中,我们已经初识中间件.本文将继续探讨这个技术.(转载请指明出于breaksoftware的csdn博客) Gin的中间件,本质是一个匿名回调函数.这 ...

  9. Colly源码解析——结合例子分析底层实现

    通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...

最新文章

  1. 打patch p0 p1区别
  2. js中的target与currentTarget的区别转
  3. 走进JVM【二】理解JVM内存区域
  4. 豆瓣9.3的纪录片《西南联大》告诉你:大学学风应如是!
  5. C语言实现简单的内存管理机制
  6. 华为p20pro投屏到笔记本_新荣耀笔记本与微软系统合作,网友:一碰即传投屏功能还有吗...
  7. Android Studio Xposed模块编写(二)
  8. android intent sender,Android7.0以上调PendingIntent.getIntent()报错
  9. 63 Defi过后,人生第一次玩DAO----超级君【2020-08-22 2234】
  10. EBS常用查询语句_查询银行账户
  11. 有关网线接法的几个问题
  12. NanUI 无边框拖拽
  13. HTML旅游网站设计与实现——东江湖旅游网站6个网页HTML+CSS+JavaScript
  14. 车载PHY的唤醒与睡眠的正确姿势
  15. rv1126 数据流
  16. 计算机/电脑为什么拥有计算能力
  17. 分布式Ruby解决之道
  18. MyBatis02:CRUD 操作,javaee教程网上购书系统
  19. 微信小程序 video 视频播放卡顿
  20. ethercat通讯移植

热门文章

  1. python线程(中途停止while循环)
  2. 我的世界服务器无限繁殖,我的世界村民无限繁殖原理 MC村民怎么无限繁殖
  3. 跨地区的劳务派遣工报酬有什么规定吗?
  4. 华为ensp报错40问题解决方法
  5. QT学习-界面中实时绘制函数图像
  6. IOS真机调试uni.scanCode调用报错,黑屏
  7. c#连接kafka_confluent-kafka-dotnet-master
  8. Linux Netfilter mangle表注册
  9. 微信如何保存表情包到手机相册
  10. Stetho工具介绍