ViewModel

45 阅读5分钟

ViewModel概览

mp.weixin.qq.com/s/I38ZvOyyz…

ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。

viewModel生命周期比Fragment/Activity长。负责为界面准备数据

这张图是在没任何设置屏幕发生转换Activity的生命周期和Viewmodel的生命周期。重建的时候,ViewModel中的数据是不会被清理的。

ViewModel优点:

  • Activity进行重建的时候,ViewModel的数据不会被回收调用。这时候可以不用通过onSaveInstanceState()方法来进行数据的存储了。而且用onSaveInstanceState()方法为了使Activity能够尽快的重建还只能存储少量的数据进行恢复
  • Activity中通常会有那种在其创建的时候获取数据,然后在其销毁的时候释放数据的方法。如果这些放在Activity中,在Activity进行重建的时候,会很浪费资源。但是如果是放在Viewmodel中的话,Activity的重建将不会导致数据的重复获取。

 当然:屏幕旋转的时候,可以通过configChanges的设置来阻止重建。但是其他的有些意外情况Activity也是有可能重建的。

ViewModel的数据如何共享以及持久化:

高版本(SDK  27)

  • ViewModelProvider持有ViewModelStore信息

  • ViewModelStore规划自身的提取方式并持有ViewModel信息

  • 通过类作为key获取具体的ViewModel实现共享

  • 在配置更变需要重建页面时,ViewModelStore会在重建前交由NonConfigurationInstance保管,并在重建后取出恢复

要点:

  • 通过ViewModelProvider持有ViewModelStore和Factory,并主要用来获取对应的ViewModelStore

  • ViewModelStore存储了key-value形式的类与ViewModel的对应。实现了数据的共享,Factory负责在需要时创建出ViewModel

  • ViewModelStore被Activity或Fragment持有,或通过注入HolderFragment间接持有

  • Activity因配置原因销毁-重建时,ViewModelStore被NonConfigurationInstances保存或被HolderFragment保存,再此需求时从保存处恢复

注意⚠️:

使用ViewModel的时候,需要注意的是ViewModel不能持有View、Lifecycle、Activity的引用。而且不能包含任何包含前面内容的类。因为这样可能会造成内存泄漏。如果需要使用Context对象。我们可以给ViewModel一个Application。Application是一个Context,而且一个应用也只会有Application

ViewModel基本原理:

在configuration changes的时候,在界面destroy的时候(ActivityThread.performDestroyActivity)通过onRetainNonConfigurationInstance方法将NonConfigurationInstances对象(里面包含ViewModel)保存起来,在重建Activity的时候在attach方法中(ActivityThread.performLaunchActivity)将上次保存的NonConfigurationInstances对象赋值给Activity的成员变量mLastNonConfigurationInstances,然后在onCreate中通过getLastNonConfigurationInstance方法获取上次保存的NonConfigurationInstances对象

源码分析:

获取ViewModel实例时,不是直接new的,而是使用ViewModelProvider来获取。入口关键点就是这里了

1.1、ViewModel的存储和获取

ViewModel是抽象类,内部没有啥逻辑,有个clear()方法会在VIewMode将被清除时调用

ViewModelProvider的构造方法,最后走到的是ViewModelStore、Factory的构造方法。

ViewModelProvider类。 是ViewModel的提供者

ViewModelStoreOwner。是ViewModel存储器的拥有者

ViewModelStore。是ViewModel存储器,用来存储ViewModel的地方

Factory。创建ViewModel实例的工厂

ViewModelStoreOwner是个接口,接口中获取ViewModelStore,即获取ViewModel的存储器

实现类有Activity/Fragment,也就是说Activity/Fragment都是ViewModel存储器的拥有者。

1.2、ViewModelStore如何存储ViewModel、以及ViewModel实例如何获取

ViewModelStore的代码:ViewModel是作为value存储在HashMap中的

1.3、 创建ViewModel实例的工厂Factory,也就是NewInstanceFactory

通过传入的class反射获取ViewModel实例。

1.4、ViewModelProvider.get(XXXViewModel.class)获取ViewModel实例,分析get方法

先从ViewModelStore中获取ViewModel实例,key是“androids.lifecycle.ViewModelProvider.DefaultKey:xxx.XXXViewModel”,如果没有获取到,就使用Factory创建,然后存入ViewModelStore

 拿到key,也就是ViewModelStore中的Map用于存ViewModel的key

从ViewModelStore中根据key获取ViewModel实例(viewmodel为value)

如果能够从ViewModelStore中获取到,则直接返回ViewModel

如果没有获取到,则用Factory创建,

然后存入ViewModelStore后返回(mViewModelStore.put(key,viewmodel))。

以上即ViewModel如何存储、实例如何获取到方法

2.2、ViewModelStore的存储和获取

Activity/Fragment是怎么实现获取ViewModelStore的,在ComponentActivity中的ViewModelStoreOwner的实现

重点:先尝试从NonConfigurationStore获取ViewModelStore实例,如果NonConfigurationInstance不存在,就new一个mViewModelStore。

注意⚠️:

在onRetainNonConfigurationInstance()方法中会把mViewModelStore赋值给NonConfigurationInstance:

在Activity因配置改变而正要销毁时,且新Activity会立即创建,那么系统就会调用onRetainNonConfigurationInstance()方法,也就是说,配置改变时 系统把ViewModelStore存在了NonConfigurationInstance中。

NonConfigurationInstance是ComponentActivity的静态内部类,非配置实例,即与系统配置无关的实例。

继续往下getLastNonConfigurationInstance()

return回的方法是在Activity.java中。返回的是Activity.Java中的NonConfigurationInstance的属性activity,也就是onRetainNonConfigurationInstance返回的实例

mLastNonConfigurationInstance是在Activity的attach方法中赋值。attach是为Activity关联上下文环境。是在Activity启动的核心流程——ActivityThread的performLaunchActivity方法中调用。这里的lastNonConfigurationInstances是存在ActivityClientRecord中的一个组件。

ActivityClientRecord是存在ActivityThread的mActivities中。

总之:ActivityThread中的ActivityClientRecord是不受activity重建的影响的。那么ActivityClientRecord中lastNonConfigurationInstances也不受影响。那么其中的Object activity也不受影响,那么ComponentActivity中的NonConfigurationInstances的ViewModelStore不受影响,那么viewModel也就不受影响了。所以 配置更改后ViewModel依然存在的原理就是这样。

ViewModel与onSaveInstanceState()区别:

1、使用场景

onSaveInstanceState是当系统自作主张销毁了activity时,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须为你提供一个保存数据的机会

ViewModel恢复数据是只有在因配置更改界面销毁重建的情况下

2、存储方式

ViewModel 存在内存中,读写速度快

onSaveInstanceState则是序列化到磁盘中

3、存储数据的限制

ViewModel可以存复杂数据,大小限制就是App的可用内存。

onSaveInstanceState只能存可序列化和反序列化的对象,且大小有限制(一般Bundle限制大小1M)

Activity的启动过程详解