Fa4910be7d00365eadc5cdb800ed4028
重学安卓:绝不丢失状态的 Activity 重建机制

往期回顾专栏目录更新动态优惠政策版权须知

温馨提示:如果这是第一次接触《重学安卓》,可通过上述链接来访问和快速了解《重学安卓》专栏、获取它的目录、试读内容,以及了解它的最新动态 和 发展状况。

截至目前,专栏已对 体系化文章 做了 1970 余次修订,数十位群友告诉我 受专栏的启发 他们也开启了写作之路。群里不定期会有小伙伴讨论适配问题、分享原创的开源库 和 提供内推机会,订阅后可随时进群交流。

前言

很高兴见到你!

上一期我们在《重学安卓:Activity 生命周期的 3 个辟谣》中,通过介绍 99% 的生命周期文章都不曾解析过的 “进程模式”,来方便大家深入理解 Activity 生命周期 的设计依据存在意义注意事项

并且,文末我还针对网文的 3 个讹传,来给大家辟了谣。

相信经过这样一次介绍,小伙伴们对生命周期有了更加深刻的认识。

那么这一期,我们来结合实际的案例,来讲解一下 Activity 的重建机制。

文章目录一览

  • 前言
  • 因为心里没底,而不敢用的状态恢复
  • 什么是重建?引发重建的场景有哪些?
  • 为何要设计出重建的机制?有何好处?
  • 状态保存和恢复的具体过程?(99% 的网文遗漏的关键细节)
  • 状态保存和恢复的的注意事项?
  • Note 2020.3.15 加餐:
    • onSaveInstanceState 的执行时机在新 API 中已确定
  • 如何避免 “配置发生变化” 导致的重建?
  • 综上
  • Note 2021.5.13 加餐:
    • 更简便 且不易出错的 “状态保存和恢复” 方式
    • App 切到后台,页面临时数据 “防丢” 的妙招

因为心里没底,而不敢用的状态恢复

源于一次阶段性的功能更新,同事向客户推送了 App 新版本,原以为万事大吉,毕竟经过一周的打磨,各项功能都已趋于流畅稳定,没想到,在客户近乎变态的数据操作下,有客户反映 “页面切换巨卡”、“速度巨慢”。

为何会产生这种情况呢?我找到编写该页面的同事询问了缘由。

同事说,问题在于每次 onPause 时,为了避免 App 切到后台被系统回收导致数据丢失,而做了大量的数据持久化操作。

那为什么不直接通过 Activity 的状态管理机制 来管理临时数据呢?

同事说,那东西“不靠谱”,用着感觉心里没底,

…… 是网上介绍 Activity 重建流程和状态管理的文章不够多吗?不是的,网文都有提到:当发生重建时,就会走 onSaveInstanceState(下文简称 “Save”)onRestoreInstanceState(下文简称 “Restore”)

然而却没有一篇深入地探究过:当走 Save 和 Restore 时,过程中究竟经历了哪些细节、背后 决定状态被成功保存和恢复的关键条件 到底是怎样的。

这使得读者在使用这个机制时忐忑不安,无法 100% 确定不会出事。

于是在经过源码分析和再三的实测检验后,我将 “重建机制” 及 “状态管理机制” 的内容整理成这篇文章,并且开源了全套测试代码(不要慌,文末链接给出)。

如果阅读完本文后,你对二者的缘起、规律有了明确的认识,从而 100% 放心地在日后工作中使用,那我的这番功夫就没白费 ~

什么是重建?引发重建的场景有哪些?

正常的生命周期流程,是页面从正常创建到销毁全流程。

而重建流程,则是在特定条件下,引发页面被销毁,并再次被创建的流程。

通常是 “系统资源的回收” 或 “配置发生变化” 导致的重建

划重点 👆 👆 👆

系统资源回收是指:

当 App 处于背景模式时,可能因系统内存不足而被回收。

例如按下 Home 键切回桌面,或是接电话跳转到电话程序,都有可能使此前的这个 App 处于背景模式。

配置发生变化是指:

当系统配置发生变化时,比如屏幕方向(旋转屏幕)、屏幕大小(折叠屏)、语言的改变等。

为何要设计出重建的机制?有何好处?

一来:对于资源回收的情况,保存状态并等到使用时再恢复,要比后台存留进程 所占的资源要小得多

二来:对于配置变化的情况,比如当屏幕方向发生变化时,唯有重建,才有机会加载不同的界面,特别如果 横屏、竖屏、折叠屏 的布局不同的话。

划重点 👆 👆 👆

上述旋屏演示来自专栏配套项目《Github:Jetpack MVVM Best Practice》

那么重建时,状态保存和恢复的具体过程如何呢?

首先,“状态” 是指支撑 UI 界面内容展示的临时数据,比如 EditText 中的文本、CheckBox 的勾选与否。

有且只有引发重建时,Activity 会走 Save 和 Restore,来保存和恢复状态。

Save 执行在 onStop 之前,但不限于在 onPause 之前或之后。

Note 2020.3.15:
自 API 28 起(CompileSDKVersion、TargetSDKVersion >= 28 并且 Android 系统版本 >= 9.0 的环境下),onSaveInstanceState 执行时机已确定为在 onStop 之后。具体可见读者 Flywith24 在 评论区 11 楼 的补充。

而 Restore 确定是执行在 onStart 之后。

其次,Activity 有两个数据结构用于保存状态:

一个是 View 的 States,专门用于存储 View 的状态;

再一个是 Instance 的 States,用于存储 View 的 States 以及 开发者在 Save 中手动保存的 Activity 成员变量。

(数据结构的具体名称可自行顺着 onSaveInstanceState 方法到源码中查询,以具体源码为准,不同版本源码可能存在差异)

top Created with Sketch.