onPause() 和 onSaveInstanceState() 中都可以保存 Activity 的数据,那二者在使用时有什么不同呢?
首先,我们为什么要保存数据?
- 持久化草稿
将草稿保存到手机存储卡上,待用户下次打开 app 时继续编辑; - 保存状态
用户 Activity A 中点击了 tab、输入了文本,然后跳到 B,内存紧张导致 A 被系统回收或者干脆 B 直接 crash 了,用户再回到 A 时,为了达到连贯的用户体验我们需要恢复 Activity 的原貌:包括文本输入框中的文字和 tab 的选中状态,这要求我们在跳到 B 前保存文本数据和临时状态数据(tab的选中状态); - 横竖屏切换前后,界面的样子要保持一致;
Activity 的2种死法:
- 正常死亡
是指完美享受了生命的各个阶段,最后走到了生命的尽头 —— onDestroy() 里面;
出现场景:用户按 Back 键; - 非正常死亡
是指尚未走进 onDestroy() 就被系统“谋杀”,即,在 onPause() 或 onStop() 阶段由于更高优先级的进程需要内存(见上图),所以被系统杀死;
出现场景:红米1手机上实际可用内存非常小,经常出现后台 APP 被杀死的情况;
也就说,Activity 被销毁前,一定会经历 onPause() 阶段,不一定会经历 onDestroy()。
onSaveInstanceState() 呢?
在正常死亡情况下,如从 Activity B 返回到 Activity A,B 的 onSaveInstanceState() 方法不会被调用。此时,A 的界面由系统保持原样,包括滚动文位置、输入框内的文本等。
在非正常死亡情况下,onSaveInstanceState() 保证在 onStop() 之前被调用,至于和 onPause() 的先后关系——可能在之前,也可能在之后。
在移动设备上打字是一件很痛苦的事,不管 Activity 怎么死的,在死之前,我们都应当把用户辛辛苦苦输入的文本/图片保存下来,存到草稿中,持久化到磁盘。
既然 onPause(),onStop(),onSaveInstanceState() 中,只有 onPause() 是百分百被调用的,那肯定是在 onPause() 中保存数据了。
但是,实际开发中,我们并不会在 onPause() 中保存数据,而是监听 Back 键。当用户按下 Back 键时提示时否保存草稿,确定时再保存,保存数据的动作是在 onBackPressed() 里面实现的,就不关 onPause() 啥事了。除非你想做到用户按下 Back 键是应用默默的把内容保存为草稿。而且,由于是用户主动退出,那些状态值就没必要保存了,下次打开 app 展示初始化时的状态。
考虑下非正常死亡的情况。
非正常死亡时,只有 onPause() 和 onSaveInstanceState(Bundle) 肯定会被调用。
非正常死亡之后,当用户又回到该 Activity 时,该 Activity 会被重新创建,为了让用户看到和离开时一样的界面,我们除了要恢复输入框内的文本数据,还要恢复像选中的 tab、列表的滚动位置等着状态。至于恢复的方法,前者是在 onCreate() 方法中从磁盘读取,而后者是没有必要持久在磁盘上的,我们只需在 onSaveInstanceState() 里面保存即可,然后在 onCreate() 或 onRestoreSaveInstance() 中读取。
注意,我们并不知道 onSaveInstanceState() 中保存的 Bundle 是否会被持久化,也许只是保存在内存里。
当然,你也可以在 onSaveInstanceState() 中保存文本数据。比如从 Activity A 跳转到 Activity B,此时 Activity A 被杀死或 Activity B 出现 crash,系统会重新创建 Activity A,为了恢复 A 的原貌,我们需要在 onSaveInstanceState() 中保存需要持久化的数据和状态值,然后在 onCreate() 里面读取出来。
综上,实际开发中,我们一般不在 onPause() 里面而是在 onSaveInstanceState() 里面保存数据(既包括可能需要持久化的,也包括状态值),然后在 onBackPressed() 里面去提示用户是否需要持久化数据,需要的话再去持久化。
onCreate(Bundle) 中的 Bundle 可能是空,而 onRestoreInstanceState(Bundle) 里面的 Bundle 一定是非空的。
参考文章: