Android开发艺术探索(研读笔记)

01-Activity的生命周期

生命周期和启动模式以及IntentFilter的匹配规则分析。

Activity的生命周期分为两个部分

  1. 典型情况下的生命周期
  2. 异常情况下的生命周期

典型情况下的生命周期分析

  • onCreate :表示Activity正在被创建。在这里可以做一些初始化的工作。
  • onRestart :表示Activity正在重新启动。当当前Activity从不可见重新变成可见状态。
  • onStart :表示Activity正在被启动。已经可见,但不在前台,无法交互。
  • onResume :表示Activity已经可见,并且出现在前台可以交互。
  • onPause :表示Activity正在停止。在这里可以做一些储存数据,停止动画等工作,但不能太耗时,因为必须onPause执行完成之后新的Activity才能Resume
  • onStop :表示Activity即将停止。可以进行一些稍微重量级的回收工作,不能太耗时。
  • onDestroy :表示Activity即将被销毁。可以进行一些回收工作和最终的资源释放。

Activity的生命周期

注意:

  • onStart和onStop是从Activity是否可见这个角度来回调的
  • onResum和onPause是从Activity是否在前台这个角度来回调的

异常情况下的生命周期分析

情况 1:资源相关的系统配置发生改变导致Activity被杀死并重新创建

比如说横屏手机和竖屏手机会拿到两张不同的图片(设定了landscape或者portrait状态下的图片)。本来手机在竖屏状态,突然旋转屏幕,由于系统配置发生了变化,在默认情况下,Activity会被销毁并且重新创建,当然我们也可以阻止系统重新创建我们的Activity。

当系统配置发生改变后,Activity会调用 onPause -> onStop -> onDestroy。

由于是异常情况终止,系统会在onStop之前调用onSaveInstanceState来保存当前Activity的状态。(与onPause没有时序关系)

Activity被系统重新创建后,系统会调用onRestoreInstanceState,把之前onSaveInstanceState方法所保存的Bundle对象作为参数同时传给onRestoreInstanceStateonCreate方法。(从时序来说,onRestoreInstanceState的调用时机在onStart之后)

而在视图方面,当Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后为我们恢复这些数据。

其实每个View都有onSaveInstanceStateonRestoreInstanceState,关于保存和恢复View层级结构,系统的工作流程如下:

onSaveInstanceState方法,系统只会在Activity即将被销毁并且有机会重新显示的情况下才会去调用它。

情况 2:资源内存不足导致低优先级的Activity被杀死

其实这种情况的数据存储与恢复过程与情况 1完全一致。

Activity的优先级情况:

  • 前台的Activity —— 正在和用户交互的Activity,优先级最高
  • 可见但非前台的Activity —— 比如Activity中弹出了一个对话框,导致Activity可见但是位于后台,无法和用户进行直接交互
  • 后台的Activity —— 已经被暂停的Activity,比如执行了onStop,优先级最低

当系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceStateonRestoreInstanceState来存储和恢复数据。而将后台工作放入Service中是一个比较好的方法。

当系统配置改变后,Activity如何不被重新创建

由于系统配置中有很多内容,如果当某项内容发生改变后,不想系统重新创建Activity可以给Activity指定configChanges属性

android:configChanges="orientation|keyboardHidden"
项目含义
mccSIM卡唯一标识IMSI(国际移动用户识别码)中的国家代码,由3位数组成,中国为460.此项 标识mcc代码发生了改变
mncSIM卡唯一标识IMSI(国际移动用户识别码)中的运营商代码,由两位数字组成,中国移动TD系统为00,中国联通为01,中国电信为03。此项标识mnc发生改变
locale设备的本地位置发生了改变们一般指切换了系统语言
touchscreen触摸屏发生了改变,正常情况下无法发生,可以忽略它
keyboard键盘类型发生了改变,比如用户使用了外插键盘
keyboardHidden键盘的可访问性发生了改变,比如用户调出了键盘
navigation系统导航方式发生了改变,比如采用了轨迹球导航,很难发生,可以忽略
screenLayout屏幕布局发生了改变,很可能是用户激活了另一个显示设备
fontScale系统字体缩放比如发生了改变,比如用户选择了一个新字号
uiMode用户界面模式发生了改变,比如是否开启了夜间模式(API8新添加)
orientation屏幕方向发生了改变,这个是最常用的,比如旋转了手机屏幕
screenSize当屏幕的尺寸信息发生了改变,当旋转设备屏幕时,屏幕尺寸会发生变化,这个选项比较特殊,它和编译选项有关,当编译选项中的minSdkVersion和targetSdkVersion 均低于13时,此选项不会导致Activity重启,否则会导致Activity重启(API13新添加)
smallestScreenSize设备的物理屏幕尺寸发生了改变,这个项目和屏幕的方向没有关系,仅仅表示在实际的物理屏幕的尺寸改变的时候发生,比如用户切换到了外部的显示设备,这个选项和screenSize一样,当编译选项中的minSdkVersion和targetSdkVersion均低于13时,此选项不会导致Activity重启,否则会导致Activity重启(API13新添加)
layoutDirection当布局方向发生变化,这个属性用的比较少,正常情况下无须修改布局的layoutDirection属性(API17新添加)

如果我们没有在ActivityconfigChanges属性中指定该选项的话,当配置发生改变后就会导致Activity重新创建。

最常用的只有localeorientationkeyboardHidden

需要修改的代码很简单,只需要在AndroidMenifest.xml中加入Activity的声明即可:

<activity
    android:name="com.dimon.MainActivity"
    android:configChanges="orientation|screenSize"
    android:label="@string/app_name">
    <intent-filter>
      <action android:name="android.intent.action.MAIN"/>
      <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
@Override
public void onConfigurationChanged(Configuration newConfig){
  super.onConfigurationChanged(newConfig);
  Log.d(TAG,"onConfigurationChanged,newOrientation:" + newConfig.orientation);
}

Activity没有重新创建,并且没有调用onSaveInstanceStateonRestoreInstanceState来存储和恢复数据,而是系统调用了ActivityonConfigurationChanged方法,这个时候我们可以加入一些自己的特殊处理了。

原作者:Dimon


集中精神,以气御剪