Activity的生命周期和启动模式

《Android开发艺术探索》-读书笔记

典型情况下的生命周期

  • 跳转时,当新Activity采用了透明主题时,当前Activity不会回调onStop
  • 跳转时,先回调当前Activity的onPause,再回调新Activity的onResumeonPause中不宜处理耗时操作。
  • onStartonStop是从Activity是否可见这个角度来回调的;onResumeonPause是从Activity是否位于前台这个角度来回调的。

异常情况下的生命周期

  • 为了防止系统配置发生改变后,Activity被重新创建,我们可以在Activity节点添加android:configChanges属性,这样Activity就不会在系统属性变化发生时重新创建,而是调用Activity的onConfigurationChanged方法。

    常见属性如下:
    local:设备的本地位置发生了变化,一般指切换了系统语言;
    keyboardHidden:键盘的可访问性发生了变化,比如用户调出了键盘;
    orientation:屏幕方向发生了变化,比如旋转了手机屏幕
    screenSize:minSdkVersion或targetSdkVersion > 13 时,添加该属性时不会导致Activity重启,反之则会。

Activity的启动模式

启动模式有4种:
  • standard: 标准模式,系统默认的模式。每次启动一个Activity都会新建一个实例,无论这个实例是否已经存在。
  • singleTop: 栈顶复用模式。如果新Activity已经位于任务栈顶,则此Activity不会被重新创建,只会回调onNewIntent方法。举个例子:当前任务栈为ABCD,当D的启动模式为singleTop时,启动D后任务栈仍为ABCD;而当D的启动模式为standard时,启动D后任务栈变为ABCDD。
  • singleTask: 栈内复用模式。只要Activity在一个栈内存在,多次启动此Activity都不会重新创建实例。简单举个例子:当前任务栈为ADCB,仍然在此任务栈启动D,系统会把D切换到栈顶,并回调onNewIntent方法,由于singleTask具有clearTop的效果,导致D上面的Activity全部出栈,所以最后当前任务的情况为AD。此外,如果指定一个新的任务栈,可以使用TaskAffinity属性来指定,这个属性不能和包名一样。
  • singleInstance: 单实例模式。加强型的singleTask模式,它具有singleTask的所有特性,此外,此模式下的Activity只能单独的位于一个新的任务栈中。
Activity指定启动模式,有两种方式:
  • 在AndroidManifest.xml中Activity节点添加android:launchMode属性。
  • 通过Intent中设置标记位来为Activity设置启动模式,例如intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

    两种方式的区别在于限定范围不同,前者无法直接为Activity设置FLAG_ACTIVITY_CLEAR_TOP标识,而后者无法为Activity指定singleInstance模式。

Activity的Flags
  • FLAG_ACTIVITY_NEW_TASK:等同于singleTask启动模式。
  • FLAG_ACTIVITY_SINGLE_TOP:等同于singleTop启动模式。
  • FLAG_ACTIVITY_CLEAR_TOP:任务栈中所有位于此Activity上面的所有Activity都要出栈。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:等同于android:excludeFromRecents="true",具有此标记的Activity不会出现在历史Activity列表中。
IntentFilter的匹配规则

启动Activity有两种方式:显式调用和隐式调用。
隐式调用需要匹配IntentFilter中所设置的过滤信息,否则无法启动;IntentFilter中过滤信息有action、category、data。

  • action匹配规则
    只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功,action匹配区分大小写。
  • category匹配规则
    Intent中如果有category那么所有的category都必须和过滤规则中的其中一个category相同,如果没有category的话那么就是默认的category,即android.intent.category.DEFAULT,所以为了Activity能够接收隐式调用,配置多个category的时候必须加上默认的category。
  • data匹配规则
    data主要由mimeTypeURI组成,其中mimeType代表媒体类型,URI的结构如下:
    <scheme>://<host>:<port>/[<path>]|[<pathPrefix>]|[pathPattern]
    例如content://com.example.project:200/folder/subfolder/etc
    scheme、host、port分别表示URI的模式、主机名和端口号,其中如果scheme或者host未指定那么URI就无效。
    pathpathPatternpathPrefix都是表示路径信息,其中path表示完整的路径信息,pathPrefix表示路径的前缀信息;pathPattern表示完整的路径,但是它里面包含了通配符(*)。
    为Intent指定完整的data,必须要调用setDataAndType方法
  • 判断是否有Activity能够匹配我们的隐式Intent
    PackageManager的resolveActivity方法或者Intent的resolveActivity方法:如果找不到就会返回null。
    PackageManager的queryIntentActivities方法:它返回所有成功匹配的Activity信息。

    针对Service和BroadcastReceiver等组件,PackageManager同样提供了类似的方法去获取成功匹配的组件信息,例如queryIntentServicesqueryBroadcastReceivers等方法

最后附上一个APP入口Activity的IntentFilter作为参考:

1
2
3
4
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>