参考资料:
每个 Activity 实例都有其生命周期。在其生命周期内,activity 在运行、暂停和停止三种可能的状态间进行转换。每次状态发生转换时,都有一个 Activity 方法将状态改变的消息通知给 activity。下图显示了 activity 的生命周期、状态以及状态切换时系统调用的方法。
请记住,只要在应用运行中设备配置发生了改变,Android 就会销毁当前 activity ,然后再新建一个 activity。因此,在设备运行中发生配置变更时,如设备旋转,需采用某种方式保存以前的数据。覆盖以下 Activity 方法就是一种实现方式:
1 | protected void onSaveInstanceState(Bundle outState) |
该方法通常在 onPause()
、onStop()
以及 onDestroy()
方法之前由系统调用。
方法 onSaveInstanceState(...)
默认的实现要求所有 activity 的视图将自身状态数据保存在 Bundle 对象中。Bundle 是存储字符串键与限定类型值之间映射关系(键-值对)的一种结构。
1 |
|
覆盖 onCreate(...)
方法时,我们实际是在调用 activity 超类的 onCreate(...)
方法,并传入收到的 bundle 。在超类代码实现里,通过取出保存的视图状态数据,activity 的视图层级结构得以重新创建。
可通过覆盖 onSaveInstanceState(...)
方法,将一些数据保存在 Bundle 中,然后在 onCreate(...)
方法中取回这些数据。当设备运行中发生配置变更时,将采用这种方式保存以前的数据。示例:
1 | public class MyActivity extends Activity { |
然后,覆盖 onSaveInstanceState(...)
方法,以刚才新增的常量值作为键,将变量值保存到 Bundle 中。示例:
1 |
|
最后,在 onCreate(...)
方法中查看是否获取了该数值。如确认获取成功,则将它赋值给变量。示例:
1 | ... |
注意,我们在 Bundle 中存储和恢复的数据类型只能是基本数据类型(primitive type)以及可以实现 Serializable 接口的对象。创建自己的定制类时,如需在 onSaveInstanceState(...)
方法中保存类对象,记得实现 Serializable 接口。
Tips:测试 onSaveInstanceState(...)
的实现是个好习惯,尤其在需要存储和恢复对象时。测试方法见这里。
覆盖 onSaveInstanceState(...)
方法并不仅仅用于处理设备旋转相关的问题。用户离开当前 acitivity 管理的用户界面,或 Android 需要回收内存时,在暂停或状态下的 activity 也会被销毁。此时,会调用 onSaveInstanceState(...)
方法。
调用 onSaveInstanceState(...)
方法时,用户数据随即被保存在 Bundle 对象中。然后操作系统将 Bundle 对象放入 activity 记录中。为便于理解 activity 记录,我们增加一个暂存状态(stashed state)到 activity 生命周期,如下图所示:
activity 暂存后,Activity 对象不再存在,但操作系统会将 activity 记录对象保存起来。这样,在需要恢复 activity 时,操作系统可以使用暂存的 activity 记录重新激活 activity。
onPause()
和 onSaveInstanceState(...)
通常是我们需要调用的两个方法。常见的做法是,覆盖 onSaveInstanceState(...)
方法,将数据暂存到 Bundle 对象中,覆盖 onPause()
方法处理其他需要处理的事情。
有时,Android 不仅会销毁 activity,还会彻底停止当前应用的进程。不过,只有在用户离开当前应用时才会发生这种情况。即使这种情况真的发生了,暂存的 activity 记录依然被系统保留着,以便于用户返回应用时 activity 的快速恢复。不过,当用户按了后退键后,系统会彻底销毁当前的 activity。此时,暂存的 activity 记录同时被清除。此外,系统重启或长时间不使用 activity 时,暂存的 activity 记录通常也会被清除。