1.典型情况下的生命周期分析
1.Activity生命周期介绍
在正常情况下,Activity会经历如下生命周期。
- onCreate: 表示 Activity 正在被创建。在这个方法中可以做一些初始化操作,比如调用 setContentView 去加载页面布局资源、初始化 Activity 所需的数据等。
- onRestart: 表示 Activity 正在重新启动。一般情况下,当当前 Activity 从不可见重新变为可见状态时,onRestart 会被调用。
- onStart: 表示 Activity 正在启动,这时 Activity 已经可见了,但还没有出现在前台,无法与用户交互。
- onResume: 表示Activity已经可见了,并且出现在前台并开始活动。注意和 onStart 的对比,onStart 和onResume都表示Activity可见了,但是onStart的时候Activity还在后台,onResume的时候才显示到前台。
- onPause: 表示Activity正在停止,正常情况下,紧接着onStop就会被创建。在特殊情况下,如果这个时候再回到当前的Activity,那么onResume会被调用。这种情况数据极端情况,用户操作很难重现这一场景。此时可以做一些停止动画、存储数据等操作,但不能太耗时,因为这会影响到新Activity的显示()onPause必须先执行完,新Activity的onResume才会执行。
- onStop: 表示Activity即将停止,可以做一些稍微重量级的回收工作,同样不能太耗时。
- onDestory: 表示Activity即将被销毁,这是Activity生命周期中的最后一个回调,在这里我们可以做一些回收工作和最终的资源释放。
2.常见的Activity生命周期执行情况
- 第一次启动Activity:onCreate -> onStar -> onResume
- 按back键回退时: onPause -> onStop -> onDestory
- 按home键回到桌面时: onPause -> onStop
- 由A页面打开新的B页面时:A-onPause -> B-onCreate -> B-onStart -> B-onResume ->A-onStop。这里有一些特殊情况,如果新的Activity采用透明主题,那么当前Activity不会回调onStop。
- 由B页面回退到A页面时: B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestory
- 常规回调时机: 从整个生命周期来说,onCreate和onDestory是配对的,分别标识着Activity的创建和销毁,并且只可能有一次调用。从Activity是否可见来说,onStart和onStop是配对的,随着页面切换或屏幕点亮熄灭,这两个方法会被调用多次。从Activity是否在前台来说,onResume和onPause是配对的,随着页面切换或屏幕点亮熄灭,这两个方法会被调用多次。
2.异常情况下的生命周期分析
在Activity异常终止时,系统会调用onSaveInstanceState来保存数据;在异常终止并重新创建后,可以通过onRestoreInstancState和onCreate来取出之前保存的数据并恢复。
情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建
比如说当前activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,activity就会被销毁并且重新创建。销毁时,其onPause、onStop、onDestory均会被调用,同时由于Activity是在异常情况下终止的,系统会调用onSaveInstanceState方法来保存当前Activity的状态。
onSaveInstanceState调用时机是在onStop之前,和onPause没有既定的时序关系,它既可呢在onPause之前调用,也可能在onPause之后调用。onSaveInstanceState只会在Activity被异常终止的情况下调用,正常情况下系统不会回调这个方法。
当activity重新创建后,系统会调用onRestoreInstanceState,并且把activity销毁时onSaveInstanceState方法保存的Bundle对象作为参数同时传递给onRestoreInstanceState和onCreate方法。
同时,在onSaveInstanceState和onRestoreInstanceState方法中,系统自动为我们做了一些恢复工作,如:文本框(EditeText)中用户输入的数据,ListView滚动的位置等,这些view相关的状态系统都能够默认为我们恢复。
情况2:源内存不足导致低优先级的activity被杀死
这里的情况和前面的情况1数据存储和恢复是完全一致的,activity按照优先级从高到低可以分为如下三种:
- 前台activity---正在和用户交互的activity,优先级最高
- 可见但非前台activity---比如activity中弹出了一个对话框,导致activity可见但是位于后台无法和用户直接交互。
- 后台activity---已经被暂停的activity,比如执行了onStop,优先级最低。
系统配置发生改变后,禁止系统重新创建Activity
当系统配置发生改变后,如果我们不想系统重新创建Activity,可以给Activity指定configChanges属性。比如不想让Activity在屏幕旋转的时候重新创建,就可以给configChanges属性添加orientation这个值,如下所示:
android:configChanges="orientation"
如果我们想指定多个值,可以使用“|”连接起来。比如为了防止旋转屏幕时Activity重启,除了orientation我们还要加上screenSize,如下所示:
android:configChanges="orientation|screenSize"
当我们在AndroidMenifest.xml文件中为Activity指定了configChanges属性后,Activity不会重新创建,并且也不会调用onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。取而代之的是系统调用了Activity的onConfigurationChanged方法,这个时候我们就可以做一些自己的特殊处理了。
最后,附上configChanges的项目和含义表
| configChanges的项目和含义 | |
|---|---|
| 项目 | 含义 |
| mcc | SIM卡唯一标识IMSI(国际移动用户识别码)中的国家代码,由三位数字组成,中国为 460。此项标识mcc代码发生了改变。 |
| mnc | SIM卡唯一标识IMSI(国际移动用户识别码)中的运营商代码,由两位位数字组成,中国移动TD系统为 00,中国联通为01,中国电信为03。此项标识mnc代码发生了改变。 |
| local | 设备的本地位置发生了改变,一般指切换了系统语言。 |
| touchscreen | 触摸屏发生了改变,这个很费解,正常情况下无法发生,可以忽略它。 |
| keyboard | 键盘类型发生了改变,比如用户使用了外插键盘。 |
| keyboardHidden | 键盘的可访问性发生了改变,比如用户调出了键盘。 |
| navigation | 系统导航方式发生了改变,比如采用了轨迹球导航,很难发生,可以忽略它。 |
| scrennLayout | 屏幕布局发生了改变,很可能是用户激活了另外一个显示设备。 |
| fontScale | 系统字体缩放比例发生了改变,比如用户选择了一个新字号 |
| uiMode | 用户界面模式发生了改变,比如是否开启了夜间模式 |
| orientation | 屏幕方向发生了改变,这个是最常用的,比如旋转了手机屏幕 |
| screenSize | 当屏幕的尺寸信息发生了改变,当旋转设备屏幕时,屏幕尺寸会发生变化,这个选项比较特殊,它和编译选项有关,当编译选项中的minSdkVersion和targetSdkVersion均低于13时,此选项不会导致Activity重启,否则会导致Activity重启 |
| smallestScreenSize | 设备的物理尺寸发生改变,这个项目和屏幕的方向没关系,仅表示在实际的物理屏幕尺寸改变的时候发生,比如用户切换到了外部的显示设备。这个选项和screenSize一样,当编译选项中的minSdkVersion和targetSdkVersion均低于13时,此选项不会导致Activity重启,否则会导致Activity重启 |
| layoutDirection | 当布局方向发生变化,这个属性用的比较少,正常情况下无需修改布局的layoutDirection属性。 |