每个 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 接口。
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 记录通常也会被清除。