基础知识
ViewModel
通过ViewModelProvider类获取,先尝试从ViewModelStore获取ViewModel实例,如果没有,则使用Factory创建,然后存入ViewModelStore。ViewModelStore
是ViewModel存储器,内部通过LinkedHashMap存储ViewModelViewModelStoreOwner
是ViewModel存储器拥有者ViewModelStoreOwner
是个接口,实现类有ComponentActivity和Fragment,也就是说ComponentActivity和Fragment 都是ViewModel存储器的拥有者- 屏幕旋转或配置发生变化会调用ComponentActivity的
onRetainNonConfigurationInstance
方法,在performDestroyActivity
阶段执行 - Activity对应的
ActivityClientRecord
变量不受Activity因配置变化而销毁重建的影响
源码分析
1.viewModel如何保存
我们从启动Activity开始,ComponentActivity构造函数中执行ViewModelStore
的初始化:
其中
getLastNonConfigurationInstance
是Activity的方法
可以看出
mLastNonConfigurationInstances
的赋值发生在Activity.attach方法内,而一开始lastNonConfigurationInstances是没有值的,为null,所以此刻getLastNonConfigurationInstance
方法返回的是null,所以ensureViewModelStore
方法内会执行:
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
即ViewModelStore的创建!
接下来到我们使用ViewModel,有创建两种方式:
1.直接使用ViewModelProvider
ViewModelProvider(this).get(XXXViewModel::class.java)
2.使用第三方依赖注入库:koin
val XXXViewModel: XXXViewModel by viewModel()
不管是哪种,最终都会走到ViewModelProvider的get方法来获取ViewModel
那我们一开始ViewModelStore内肯定是不存在ViewModel的,则使用fatory创建一个,内部使用了反射,然后放入ViewModelStore,内部通过LinkedHashMap存储ViewModel,可以自己看下源码
好了,此时我们的ViewModelStore内部存储了ViewModel实例
接下来我们旋转屏幕,Aactivity1销毁,Aactivity2重建,Aactivity1销毁时,执行到performDestroyActivity
时,会执行activity的retainNonConfigurationInstances
方法
ComponentActivity
重写了这个方法:
这个方法很重要,我们一起来看下,这个时候,viewModelStore肯定不为null,所以两个if都不会执行,直接new一个
NonConfigurationInstances
出来,把当前的viewModelStore赋值给NonConfigurationInstances
,其中viewModelStore有我们的viewModel!所以上上图中的activity局部变量是NonConfigurationInstances
实例,所以咱们的viewModel一路传递到了performDestroyActivity
中的r.lastNonConfigurationInstances
中,即ActivityClientRecord
中!
我们可以得出结论:我们旋转屏幕,Aactivity1销毁时,会把我们的viewModel保存到
ActivityClientRecord
中,又因为ActivityClientRecord
不受Activity因配置变化而销毁重建的影响,所以它能够帮我们安全得保留了数据
2.viewModel如何获取
我们在前面讲到,启动Activity时,ComponentActivity构造函数中执行了ViewModelStore
的初始化:
此时,
getLastNonConfigurationInstance
会返回上次在ActivityClientRecord
中保留的NonConfigurationInstances
实例,里面存储着咱们的viewModelStore以及里面的viewModel,所以nc!=null,ViewModelStore
直接被赋值,不会执行下面红框内的new
初始化,为什么这次的getLastNonConfigurationInstance
方法不是null,因为在Activity.attach方法中,我们对mLastNonConfigurationInstances
赋值了,而这次赋值不再是null!
顺便给练习项目求个Star🌟🌟🌟,万分感谢🙏🙏🙏:
github.com/stewForAni/…