ViewModel 甫一发布,便成为了 Jetpack 中的核心组件之一。我们在 2019 年做的一份开发者问卷显示,超过 40% 的 Android 开发者已经在自己的应用中使用了 ViewModel。ViewModel 可以将数据层与 UI 分离,而这种架构不仅可以简化 UI 的生命周期的控制,也能让代码获得更好的可测试性。如果想了解更多,可以参考 ViewModel: 简单介绍视频和官方文档。
官方文档
https://developer.android.google.cn/topic/libraries/architecture/viewmodel
由于 ViewModel 是许多功能实现的基础,我们在过去的几年里做了许多工作来改进 ViewModel 的易用性,也让它能够更加简便地与其他组件库相结合。下面的文章中,我将介绍 ViewModel 的四种集成方式:
ViewModel 中的 Saved State —— 后台进程重启时,ViewModel 的数据恢复;
在 NavGraph 中使用 ViewModel —— ViewModel 与导航 (Navigation) 组件库的集成;
ViewModel 配合数据绑定 (data-binding) —— 通过使用 ViewModel 和 LiveData 简化数据绑定;
viewModelScope —— Kotlin 协程与 ViewModel 的集成。
ViewModel 的 Saved State —— 后台进程重启时,ViewModel 的数据恢复
于 lifecycle-viewmodel-savedstate 的 1.0.0-alpha01 版本时加入
支持 Java 和 Kotlin
onSaveInstanceState 带来的挑战
ViewModel 一发布,执行 onSaveInstanceState 的相关的逻辑时要如何操作 ViewModel,便成为了一个令人困惑的问题。Activity 和 Fragment 通常会在下面三种情况下被销毁:
从当前界面永久离开: 用户导航至其他界面或直接关闭 Activity (通过点击返回按钮或执行的操作调用了 finish() 方法)。对应 Activity 实例被永久关闭;
Activity 配置 (configuration) 被改变: 例如,旋转屏幕等操作,会使 Activity 需要立即重建;
应用在后台时,其进程被系统杀死: 这种情况发生在设备剩余运行内存不足,系统又亟须释放一些内存的时候。当进程在后台被杀死后,用户又返回该应用时,Activity 也需要被重建。
在后两种情况中,我们通常都希望重建 Activity。ViewModel 会帮您处理第二种情况,因为在这种情况下 ViewModel 没有被销毁;而在第三种情况下, ViewModel 被销毁了。所以一旦出现了第三种情况,便需要在 Activity 的 onSaveInstanceState 相关回调中保存和恢复 ViewModel 中的数据。我在 ViewModels: 持久化、onSaveInstanceState()、恢复 UI 状态与加载器一文中更加详细地描述了这两种情况的区别。
ViewModels: 持久化、onSaveInstanceState()、恢复 UI 状态与加载器
https://medium.com/androiddevelopers/viewmodels-persistence-onsaveinstancestate-restoring-ui-state-and-loaders-fc7cc4a6c090
Saved State 模块
现在,ViewModel Saved State 模块将会帮您在应用进程被杀死时恢复 ViewModel 的数据。在免除了与 Activity 繁琐的数据交换后,ViewModel 也真正意义上的做到了管理和持有所有自己的数据。
ViewModel 的这一新功能是通过 SavedStateHandle 实现的。SavedStateHandle 和 Bundle 一样,以键值对形式存储数据,它包含在 ViewModel 中,并且可以在应用处于后台时进程被杀死的情况下幸存下来。诸如用户 id 等需要在 onSaveInstanceState 时得到保存下来的数据,现在都可以存在 SavedStateHandle 中。
ViewModel Saved State
https://developer.android.google.cn/topic/libraries/architecture/viewmodel-savedstate
SavedStateHandle
https://developer.android.google.cn/reference/androidx/lifecycle/SavedStateHandle.html
设置 Save State 模块
现在让我们看看如何使用 SaveState 组件。注意接下来的代码会和 Lifecycles Codelab 第六步中的一段代码十分相似。那段是 Java 代码,而接下来的是 Kotlin 代码:
第一步: 添加依赖
SaveStateHandle 目前在一个独立的模块中,您需要在依赖中添加:
def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
注意,本文发布时 lifecycle 组件的最新稳定版为 2.2.0,如果您希望持续关注相关组件库的进展,可以查看 lifecycle 版本发布文档。
Lifecycles Codelab
https://codelabs.developers.google.com/codelabs/android-lifecycles/#6
lifecycle 版本发布文档
https://developer.android.google.cn/jetpack/androidx/releases/lifecycle#viewmodel-savedstate-1.0.0-alpha01
第二步: 修改调用 ViewModelProvider 的方式
接下来,您需要创建一个持有 SaveStateHandle 的 ViewModel。在 Activity 或 Fragment 的 on