ViewModel概览
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的启动过程详解