上篇文章提到,虽然viewModel
要比onSaveInstanceState
简单,但是viewModel
只能在屏幕旋转和语言切换后(即配置变更时)的页面重建维持数据,当页面意外销毁时数据无法恢复(viewModel也会重建),而这点onSaveInstanceState
可以做到。关于意外销毁,我们暂且理解成非配置变更引起的销毁重建,比如内存不足等场景。
本文源码基于SDK 29
问题复现
引入依赖:
1 | def lifecycle_version = "2.2.0" |
创建ViewModel
,
1 | class CommonViewModel extends ViewModel { |
在布局文件中使用,
1 | <layout xmlns:android="http://schemas.android.com/apk/res/android" |
在act中使用,
1 | class ViewModelActivity extends BaseActivity { |
在onCreate方法中,新加了savedInstanceState
的取值操作,同时重写了onSaveInstanceState
方法存储时间,那么如何模拟页面被意外销毁呢,可以在开发者选项中选中不保留活动-用户离开后即销毁每个活动
,开启后,运行app,然后按home键引起页面意外销毁,然后回到页面,查看日志:
可见当页面意外销毁时,viewModel并不能很好的维持数据。
解决
如果需要让ViewModel
能在页面意外销毁时维持数据,那就需要结合SavedStateHandle
使用了,新建一个ViewModel
,
1 | class SavedStateViewModel extends ViewModel { |
然后在act中加入:
1 | //ViewModelActivity.java |
运行到该页面,点击home键触发意外销毁,然后回到页面,查看日志,
发现虽然mSavedStateViewModel
不再是同一个实例,但是数据是可以恢复的。
至于原理,大致的思路就是在SavedStateViewModelFactory
中,
1 | //SavedStateViewModelFactory.java |
而在SavedStateHandleController
中,
1 | //SavedStateHandleController.java |
即本质还是通过Bundle
的序列化和反序列化来恢复数据的。