黄金龙的博客

Activity的生命周期和启动模式的总结

Activity毫无疑问是Android中最重要的组件之一了,做好一个android程序,首先就得要hold住他的生命周期。

Activity的生命周期的总结,以及注意的细节

先来个图

Activity生命周期图

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

Activity的常用生命周期我们不做讨论,一个Activity从创建到结束的基本回调为:onCreate->onStart->onResume->onPause->onStop->onDestroy。
从整个生命周期来说,onCreate跟onDestroy是相对的,分别标识着Activity的创建和销毁。onStart跟onStop是相对的,分别标识着Activity是否完全可见。onResume跟onPause是相对的,分别标识着Activity是否在前台。

生命周期细节分析

  • onStart跟onResume、onPause跟onStop从他们的描述上讲是差不多的,甚至在实际开发的过程中我们只保留其中的一对。onStart跟onStop是相对的,分别标识着Activity是否完全可见。onResume跟onPause是相对的,分别标识着Activity是否在前台。其他情况没有本质区别。

  • ActivityA中的onPause要比即将打开的ActivityB的onResume先执行,即前一个AcitivtyA要先执行完onPause之后后一个ActivityB就开始走自己的生命周期了,当ActivityB位于前台之后(即执行完onResume)ActivityA的onStop才执行,基于此我们可以知道必须在onPause处理耗时少的任务,要不然会影响下一个Activity的执行

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

Activity除了受用户操作导致的正常生命周期方法的调度,还会存在一些异常的情况:比如当系统内存不足、资源相关的系统配置发生改变。

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

典型的是当我们旋转手机的时候,由于横排导致需要重新加载各种横屏资源,所以会导致Activity的杀死重建,会依次执行onPause、onStop、onDestroy,同时由于Activity是在异常情况下终止的,所以系统会调用onSavaInstanceState来保存异常情况前的状态。onSavaInstanceState调用在onPause之后,跟onStope没有明确的次序关系,有可能在前也有可能在后。Activity重新加载会依次执行onCreate、onStart、onRestoreInstanceState来恢复状态。也可以直接在onCreate中判断bundle是否为空来恢复之前的状态。当Activity异常终止并重新创建时,系统会自动帮我们保存并恢复Activity的视图结构,以及数据,如文本框中用户输入的数据,ListView滑动的位置等。

当内存不足导致的优先级低的Activity被杀死

这种情况是比较常见的。在国内许多定制的系统中,为了保证手机的运行速度,会频繁的进行检查杀死优先级低的Activity,有时候即使内存足够也会面临被杀死的情况。Activity按照优先级从高到低分别为

  1. 前台Activity,正在和用户交互的Activity,优先级最高
  2. 可见但非前台Activity,比如Activity弹出了一个对话框,此时的Activity是可见的,但是无法和用户交互,
  3. 后台Activity,已经被暂停的Activity,优先级最低,当内存不足时最容易被处理

Activity的启动模式

Activity的LaunchMode

如果没有Activity的启动模式,我们在启动的时候只能为单一的跳转,非常不灵活。当我们多次启动同一个Activity,系统会创建多个Activity实例一一放在任务栈中,当我们单机back键后Activity会一一回退。任务栈是一种“后进先出”的栈结构。当栈中无任务Activity后系统会回收这个任务栈。4种启动模式介绍,

  1. standard:标准模式。这也是系统默认的模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在,一个任务栈中可以有多个实例,一个实例也可以存在于多个栈中。启动的时候在哪一个栈中启动就会直接加到那个任务栈中。
  2. singleTop:栈顶复用模式。在这种模式下,如果新的Activity处于栈顶,那么此Activity不会重新创建,同时他的onNewIntent方法会被调用,通过此方法我们可以得到当前请求的信息。而onCreate、onStart、onResume等方法没有被调用,因为他并没有发生改变。但是如果新的Activity不是处于栈顶,那么新的Activity会被重新创建并放入到栈顶。
  3. singleTask:栈内复用模式。这是一种单实例模式,即当新的Activity存在于栈中,新的Activity会把其之上的Activity全部清除,让自己成为栈顶,并且栈中只会有一个相同的实例。
  4. singleInstance:单实例模式。这其实是singleTask模式的加强版,即具有此模式的新的Activity会单独的位于一个任务栈中。

上面介绍的几种启动模式,我们假设目前有两个任务栈,前台任务栈A、B,后台任务栈C、D。当我们从B启动D的时候,会拉起整个后台任务栈,即C、D,当点击back键会先返回到C,再点击返回到B。当从B启动C的时候,D不会跟着拉起来。用图解释可能会更加易懂:
任务栈图
任务栈图

Activity的Flags

Activity的Flags有很多,这里主要介绍几个比较常见的标记位。标记位的作用很多,有的标记可以设置Activity的启动模式,有的标记位可以影响Activity的运行状态,还有的标记位可以设置视图的显示。大部分情况下我们不需要为Activity设置标记位。

  • FLAG_ACTIVITY_NEW_TASK:这个标记为的作用是指定“singleTask”启动模式,其效果和在manifest设置效果相同
  • FLAG_ACTIVITY_SINGLE_TOP:这个标记位的作用是为Activity指定“singleTop”启动模式,其效果和在manifest设置效果相同。
  • FLAG_ACTIVITY_CLEAR_TOP:具有此标记位的Activity,当他启动时,在同一个任务栈中所有位于他顶部的Activity都要出栈,这个模式一般和FLAG_ACTIVITY_NEW_TASK配合使用。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有此标记为都Activity不会出现在Activity历史列表中,等同于在minifest中设置属性android:excludeFromRecent=”true”.

IntentFilter的匹配规则

启动Activity分为两种,显示调用和隐式调用。显示调用需要明确指明被调用对象的组件信息,包括包名和类名,而隐式调用则不需要明确指定组件信息,原则上一个Intent不能即为显式又为隐式,如果二者共存的话显示为主。隐式调用需要明确组件的IntentFilter,如果不匹配则无法启动目标Activity。IntentFilter的过滤信息为action、category、data。

  • action的匹配规则要求action存在且必须和过滤规则中的其中一个action相同,只要有一个相同就可以,如果设置了多个action,只要有一个action匹配Intent就可以。
  • category的匹配规则要求如果Intent中存在category,那么所有的category必须和过滤规则中的其中一个category相同。换句话说,对于每一个category都必须必配已经定义了的。Intent中可以没有category,如果一旦有就必须完全匹配。
  • data的匹配规则跟action类似

以上就是关于Activity的一些总结,其中的细节可以查看相关文档。