为之于未有,治之于未乱。
Activity作为Android四大组件之首,它的生命周期和启动模式在平时的开发中,重要而又常见,熟练的掌握相关知识,对于Activity的灵活运用会有很大的帮助,下面将对相关重要知识点做简单梳理。
Activity的生命周期
- Activtivity的生命周期:

- Fragment的生命周期:

Tips:
- Activity采用透明主题时,不会回调onStop
- 旋转屏幕使Activity不会重新创建的方法:
android:configChanges=”orientation|keyboardHidden|screenSize”
Activity的启动模式
Activity的LaunchMode
有时候为了满足项目特殊需求,我们就必须使用Activity的启动模式,下面将简单的介绍一下四种启动模式:standard、singleTop、singleTask、singleInstance。
这些模式分为两大类,“standard”和“singleTop”Activity 为一类,“singleTask”和“singleInstance”为另一类。前两者启动模式的Activity可以被实例化多次。
- standard:标准模式
每次启动一个Activity都会创建一个新的实例 - singleTop:栈顶复用模式
如果目标任务的顶部已存在一个Activity实例则系统会通过调用该实例的onNewIntent()方法向其传送Intent,而不是创建新的Activity实例。 - singleTask:栈内复用模式
如果任务栈中已存在该Activity的实例,则系统会通过调用该实例的onNewIntent()方法向其传送Intent,而不是创建新的Activity实例,同时会将位于该实例顶部的其他实例全部移除出栈。
此处将受TaskAffinity属性影响(用于指定Activity所关联的Task),系统将查询是否有该Activity需要的任务栈,如果不存在,就会重新创建一个任务栈,然后创建Activity的实例;如果该任务栈已存在,则继续查询是否已存在该Activity的实例,如果不存在,则创建实例并放入栈中,如果存在,则将该实例顶部的其他实例全部推出栈。 - singleInstance:单例模式
此模式具备singleTask模式的所有特性,此外具有此种模式的Activity只能单独地位于一个任务栈中。
taskAffinity:标识一个Activity所需要的任务栈的名称,默认情况下,所有Activity所需的任务栈的名称为应用的包名;通常和allowTaskReparenting属性结合使用。
allowTaskReparenting:允许其转移任务栈,值为字符串,中间必须含有包名分隔符“.”。
当一个应用A启动了应用B的某个Activity后,点击home键回到桌面,再点击B应用桌面图标,如果该Activity的allowTaskReparenting属性为true时,该Activity会直接从应用A的任务栈转移到B的任务栈中,同时B应用将直接进入该Activity,而不是B应用的主Activity。
Activity的Flags
Activity的Flags有很多,详情请查看官方文档,这里介绍几种比较常用的标记位。标记位的作用有很多,有的可以设定Activity的启动模式。
- FLAG_ACTIVITY_NEW_TASK:
为Activity指定“singleTask”启动模式 - FLAG_ACTIVITY_SINGLE_TOP:
相当于LauchMode中的singleTop。 - FLAG_ACTIVITY_CLEAR_TOP:
在同一个任务栈中所有位于它上面的Activity都要出栈。这个标记位一般会和singleTask启动模式一起出现,在这种情况下,被启动的Activity的实例如果已经存在,系统就会调用它的onNewIntent。如果被启动的Activity采用standard启动模式,那么它连同它之上的Activity都要出栈,系统会创建新的实例并放入栈顶。 - FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:
具有这个标记位的Activity不会出现在历史Activity的列表中,如果调出的Activtivity只是一个功能片段,并没有实际的意义,此时长按Home键调出最近使用过的程序类表中,将不会出现此Activity。 - FLAG_ACTIVITY_NO_HISTORY:
使用这个FLAG启动的Activity,一旦退出,它不会存在于栈中,比如说,原来是A,B,C这个时候在C中以这个FLAG启动D的,D再启动E,这个时候栈中情况为A,B,C,E。
LaunchMode和Flags的运用
设置Activity启动模式的两种方法:
通过在AndroidMenifest.xml中设置:
1234<activityandroid:name=".ui.activity.MainActivity"android:screenOrientation="portrait"android:launchMode="singleTask"/>通过Intent设置标志位
123Intent intent = new Intent(this,MainActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);
以上两种方式都可以为Activity设置启动模式,当两者同时存在时,将以第二种为准,第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识,而第二种则无法为Activity指定singleInstance模式。
IntentFilter的匹配规则 官方地址
启动Activity分为显示调用和隐式调用,显示调用需要明确地指定被启动对象的组件信息,包括包名和类名,而隐式调用不需要明确指定组件信息,但需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息。只有同时匹配过滤列表中的action、category、data信息,才能完成匹配并成功启动目标Activity,一个Activity中可以拥有多个IntentFilter,一个Intent只要能匹配任何一组IntentFilter即可成功启动对应的Activity。
action的匹配规则 官方地址
action是一个字符串,系统预定义了一些action,同时我们也可以自定义,每个过滤规则中可以有多个action。只要Intent中的action与过滤规则中的任何一个action字符串值完全一样(区分大小写),即可匹配成功,即action的匹配要求Intent中的action存在且必须和过滤规则中的其中一个action相同。
category的匹配规则 官方地址
category是一个字符串,系统预定义了一些category,同时我们也可以自定义,每个过滤规则中可以有多个category。Intent中所有的category必须和过滤规则其中一个category相同(字符串值完全一样,区分大小写)。系统在调用startActivity或者startActivityForResult时会默认为Intent加上“android.intent.category.DEFAULT”这个category,所以为了我们的activity能够接收隐式调用,就必须在intent-fileter中指定“android.intent.category.DEFAULT”。
data的匹配规则官方地址
data的匹配规则和action类似,如果过滤规则中定义了data,那么Itent中必须也要有定义可匹配的data。data由mimeType和URI组成,mimeType指媒体类型,比如image/jpeg、audio/mpeg4-generic和video/* 等,可以表示图片、文本、视频等不同的媒体格式;而URI中包含数据比较多一些,结构如下:
|
|
|
|
Scheme:URI的模式,比如http、file、content等,URI中必须指定Scheme;
Host:URI的主机名,比如www.baidu.com,URI中必须指定Host;
Port:URI中的端口号,如果80,仅当URI中指定了scheme和host参数的时候,port参数才有意义;
Path、PathPrefix、PathPattern:表述路径信息,其中path表述完整的路径信息,PathPattern也表示完整的路径信息,但是它里面可以包含通配符“ * ”,“ * ”表示0个或多个任意字符,需要注意的是,由于正则表达式的规范,如果想要表示真实的字符串,那么“ * ”要写成“ \\* ”,“ \ ”要写成“ \\\\ ”;pathPrefix表示路径的前缀信息。
data的匹配规则和action类似,它要求Intent中必须含有data数据,并且data数据能够完全匹配过滤规则中的某一个data。
实例一:
这种规则指定了媒体类型为所有类型的图片,那么Intent中的mimeType属性必须为“ image/* ”才能匹配,此时虽然过滤规则没有指定URI,但Intent中的URI部分的scheme必须为content或者file才能匹配,如下所示:
另外,如果要为intent指定完整的data,必须要调用setDataAndType方法,setData和setType方法会清除对方的值。
实例二:
这种规则指定了两组data规则,且每组都指定了完整的属性值,既有URI又有mimeType,
关于data还有一个特殊情况,这也是它和action不同的地方,如下两种写法作用是一样的:
最后,当我们通过隐式方式启动一个Activity的时候,可以先判断是否有Activity能够匹配我们的隐式Intent,判断方法有两种:采用PackageManager的queryIntentActivities方法,或者Intent的resolveActivity方法,如果找不到匹配的Activity就会返回null。
两个方法中的flags需要使用MATCH_DEFAULT_ONLY这个标记位,这个标记位的含义是仅仅匹配那些在intent-filter中声明了“android.intent.category.DEFAULT”这个category的Activity,其中原因在category匹配规则中已有说明。