0%

第1章——Activity 生命周期和启动模式

Activity 的生命周期全面分析

本节将分为两部分内容,一部分是典型情况下的生命周期,一部分是异常情况下的生命周期(比如被系统回收或者由于当前设备Configuration 发生改变而导致 Activity 被销毁重建)。

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

正常情况下,Activity 会经历如下生命周期:

  1. onCreate : 表示Activity 正在创建,这是生命周期第一个方法。
  2. onRestart : 表示Activity 正在重新启动。一般情况下,当前Activity 从不可见重新变为可见时,onRestart 就会被调用。
  3. onStart : 表示Activity 正在被启动,这时候 Activity 已经可见了,但是还没出现在前台,无法和用户交互。可以理解为 Activity 已经显示出来了,但是我们还看不到
  4. onResume : 表示 Activity 已经可见了,并且出现在前台可以交互。
  5. onPause: 表示 Activity 正在停止,正常情况下,紧接着 onStop 会被调用;在特殊情况下,如果这个时候快速地再回到当前 Activity ,那么 onResume 将会被调用。此时可以做一些存储数据、停止动画等工作,但是注意不能太耗时,因为onPause必须先执行完,新Acitivty 的 onResume 才会执行
  6. onStop : 表示 Activity 即将停止,可以做一些稍微重量级的回收工作,同样不能太耗时。
  7. onDestroy: 表示 Activity 即将被销毁,这是Activity 生命周期中的最后一个回调,我们可以做一些回收工作和最终的资源释放。

以下再针对 Activity 的生命周期具体说明:

  • 针对特定的Activity,第一次启动回调如下: onCreate->onStart->onResume
  • 打开新的Activity 或者(按Home键)回到桌面的时候,回调 onPause->onStop ;这里有种特殊情况,打开的新Activity 如果是透明主题(意味着当前Activity还是可见的),那么当前Activity 不会回调 onStop 。
  • 当用于再次回到原来的 Activity 时,回调 onRestart->onStart->onResume
  • 当用户按返回键返回上一个页面时,回调 onPause->onStop->onDestroy
  • 从整个生命周期来看,onCreate与onDestroy是配对的,分别标识着Activity的创建与销毁;onStart与onStop是配对的,标识着Activity是否可见;onResume 与 onPause 是配对的,标识着Activity是否在前台

一个问题:当前 Activity 标识为 A,启动一个新的Activity 标识为 B,那么B的onResume 和 A 的onPause 哪个先执行?

由上面的描述可知是限制性A的 onPause,再执行 B 的onResume ,具体看源码,官方文档也是这么解释(Always followed by onPause())。

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

1、资源相关的系统配置发生改变导致Activity被杀死并重建

如果没有做特殊处理,当横竖屏切换的时候,由于系统配置发生了改变,Activity 会加载不同的资源(比如横竖屏加载两张不同图片),此时 Activity 会被销毁并且重新创建。由于 Acitivity 是在异常情况下终止的,因此在销毁Activity的时候,确切来说是在onStop之前(但是跟onPause没有顺序关系,有可能在其之前,也可能在其之后)会调用 onSaveInstanceState 来保存当前 Activity 状态

Activity 被重新创建后,会把销毁时 onSaveInstanceState 方法保存的Bundle对象作为参数传给 onCreate 方法和 onRestoreInstanceState 方法,因此可以从这两个方法恢复之前保存的数据。从时序上来说,onRestoreInstanceState 调用时机在 onStart 之后。

这两个方法恢复数据的区别是:onRestoreInstanceState 一旦被调用,其参数 savedInstanceState 是一定有值的,我们不需要额外地判空;而 onCreate 中的数据是可能为空的,官方文档建议采用 onRestoreInstanceState 去恢复数据。

如果没有覆写的话,onSaveInstanceState 和 onRestoreInstanceState 方法中,系统会自动为我们做一定的恢复工作。

2、资源内存不足导致低优先级Activity被杀死

Activity 按照优先级从高到低可以分为如下三种:

(1)前台Activity——正在和用户交互的Activity,优先级最高
(2)可见但非前台Activity——比如Activity中弹出了dialog,导致Activity可见但是位于后台无法和用户直接交互。
(3)后台Activity——已经被暂停的的Activity,优先级最低。

我们知道,当系统配置发生改变时,Activity 会被销毁并重新创建,当然我们也可以通过给 Activity 指定configChanges 属性来阻止销毁重建:

android:configChanges=”orientation”

当然这个属性可以配置的项目还有很多,比如切换系统语言、使用了新字号、界面模式改变(比如 是否开启/关闭夜间模式)。

Activity 的启动模式

  • standard: 标准模式。不复用,每次请求都创建新实例,并且就运行在启动它的那个Activity所在的栈。
  • singleTop: 栈顶复用模式 。如果实例位于任务栈的栈顶就复用,复用时调用 onNewIntent方法,否则就创建新的实例。
  • singleTask: 栈内复用模式。当前栈内没有实例,则创建实例放入栈中;如果实例在当前栈内,则复用,复用时调用 onNewIntent方法,并把它之上的Activity出栈。
  • singleInstance: 单例模式。只能单独位于一个任务栈中,只要这个实例存在,后续的请求均不会创建新的Activity。复用时调用 onNewIntent方法。

在使用 ApplicationContext 启动standard 模式的Activity时会报错:

Callking startActivity from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag

这是因为standard模式的Activity 默认会进入启动它的Activity所属的任务栈中,由于非Activity类型的Context 没有所谓的任务栈,所以会报错。解决这个问题的方法是为待启动的Activity指定 FLAG_ACTIVITY_NEW_TASK 标记,这样启动的时候会为它创建一个新的任务栈(体会下,这时候实际上是以singleTask模式启动的)

参考其他博客的启动模式的原理

点击launcher 的startactivity 会调用到Instrumentation的execStartActivity,之后交给AMS 来处理启动操作,之后调用 ActivityStackSupervisor 的 startActivityMayWait 方来启动,而ActivityStackSupervisor 是管理Activity堆栈的类

另外提一下,Activity 在AMS中的形式是 ActivityRecord,task在AMS 中的形式是 TaskRecord,进程在 AMS 中的管理形式为 ProcessRecord

判断启动模式,根据当前的Activity 和 要启动的Activity 的启动模式,根据相应的启动模式设置launchFlags

在Android 5.0上 在 ActivityStackSupervisor 类的startActivityUncheckedLocked 里面判断launchmode

以上内容参考自简书的博客上的内容

Activity 的Flags

Activity 的Flags很多,这里分析比较常用的几个:

  • FLAG_ ACTIVITY_ NEW_ TASK

为Activity 指定singleTask启动模式,其效果和在XML中指定 singleTask 启动模式相同

  • FLAG_ ACTIVITY_ SINGLE_ TOP

为Activity 指定 singleTop 启动模式,其效果和在XML中指定 singleTop 启动模式相同

  • FLAG_ ACTIVITY_ CLEAR_ TOP

具有此标记的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈,这个标记为一般会和FLAG_ACTIVITY_SINGLE_TOP标记位一起出现。由前面的分析可知,singleTask启动模式默认具有此标记位效果。

  • FLAG_ ACTIVITY_ EXCLUDE_ FROM_ RECENTS

具有这个标记位的Activity不会出现在历史Activity列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候,这个标记比较有用。这个标记等同于xml中指定Activity 的属性 android:excludeFromRecents = “true”

IntentFilter 的匹配规则

谢谢你的鼓励