一、LaunchMode
预备知识:任务栈(回退栈),后进先出
1.standard(标准模式):默认启动模式,每创建一个新Activity,都会产生一个新的Activity实例并且放入相应的任务栈中。和典型的栈调用数据类似没多大区别。
2.singleTop(栈顶复用模式):如果要新建的Activity本身已经有一个Activity实例位于栈顶时,那么这个Activity不会被重新创建,而是会回调onNewIntent方法取出当前请求的信息,而这个新建的Activity不会被系统调用onCreate、onStart方法。注意的是,该模式只使用于新Activity已经位于栈顶。否则的话还是会创建新的Activity并且进行压栈操作。
3.singTask(栈内复用模式):只要Activity在想要的任务栈中存在,会将栈内存在的Activity做置顶操作(由于“后进先出”,会clear top)。而如果在栈内不存在时,会直接创建并压栈。具体一点,想要的任务栈如果不存在,则创建一个任务栈然后创建实例入栈;如果想要的任务栈存在,则看是否存在实例,若存在则clearTop且onNewIntent,不存在则创建实例入栈。
4.singleInstance(单实例模式):加强的singleTask模式,除了具有singTask的一切特性外,还加强了一点,就是具有此模式的Activity只能单独的位于一个任务栈中。也就是说,在它启动的时候,系统会为它分配一个新的任务栈。由于singleTask的复用性,在其他需要创建Activity的时候,都不会创建新的Activity。
扩展:TaskAffinity(Activity想要的任务栈)
每个Activity都会有TaskAffinity参数,标识了Activity所需要进入的任务栈的名字。默认是包名,也就是当前应用下的任务栈。两种情况(其他情况没有意义):
1.当TaskAffinity和singleTask启动模式配对使用的时候:singleTask的activity会运行在TaskAffinity指定名字的任务栈中。
2.当TaskAffinity与allowTaskReparenting结合的时候:在这种情况下,如果该Activity的allowTaskReparenting设置为true的时候,这个Activity会直接进入后台,直到当和TaskAffinity名字相同的任务栈进入前台的时候,此时的Activity会转移到该任务栈中并处于栈顶位置。 书中例子:先有应用A、B。当在A中启动B的一个ActivityC,然后按Home键回到桌面,打开B应用。此时你会发现显示出来的是ActivityC。
用法<application android:allowTaskReparnting="true/false"></application>:是否允许activity更换从属的任务,比如从短信息任务 切换到浏览器任务。用来标记Activity能否从启动的Task移动到有着affinity的Task(当这个Task进入到前台时)——“true”,表示能移动,“false”,表示它必须呆在启动时呆在的那个Task里。
如果这个特性没有被设定,设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为“false”。
一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着affinity的Task中。典型用法是:把一个应用程序的Activity移到另一个应用程序的主Task中。
例如,如果e-mail中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的,但是,现在它作为e-mail Task的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见,并且,当e-mail Task再次进入前台时,就看不到它了。
Actvity的affinity是由taskAffinity特性定义的。Task的affinity是通过读取根Activity的affinity 决定。因此,根据定义,根Activity总是位于相同affinity的Task里。由于启动模式为“singleTask”和 “singleInstance”的Activity只能位于Task的底部,因此,重新宿主只能限于“standard”和“singleTop”模式。
注:在Intent中设置标志位来指定启动模式 比 通过AndroidMenifest.xml为Activity指定启动模式 优先级高。
二、IntentFilter匹配规则(隐式启动)
IntentFilter的过滤信息包括三种:action、category、data。一个Activity可以设定多个IntentFilter,只要有其中一组IntentFilter完全匹配,可以开启该Activity。
action的匹配规则
action的本质是一个字符串,其作用是描述Intent所触发的动作的名称。在IntentFilter中,我们可以定义多个action,只要有一个action和Intent传递的信息匹配,那么就算配合成功。注意的是,系统本身预定义了一些action,代表可启动的一些预定义的Activity,比如拨号界面等这些预定义的action集中放在android.intent.action下,调用的时候从里面选取,比如Intent.ACTION_CALL
category匹配规则
category和action的本质是一致的,但代表的意义不同,category描述的是目标组件的类别信息,表明这个目标可以干些什么。当然,我们也可以给它进行自定义的设置。 而关于category的匹配规则,大致如下:如果Intent中含有category,那么不管你有几个,都需要和目标Activity在IntentFilter中设定的category匹配。
data的组成
data由两部分组成:mimeType 和URI。其中,mimeType指的媒体类型,可以表示图片image/jpeg,文本text/html ,音频audio/mpeg4-generic 和视频video/*等。而URI表示统一资源标识符(Uniform Resource Identifier),用以制定所需资源的存储路径。其结构如下:
<scheme>://<host>:<port>:/[<path>|<pathPrefix>|<pathfrefix>]
结构说明如下:
scheme:URI的模式,比如http、file等
host:URI的主机名,即当前资源所在的主机的IP地址,可以用域名表示,如www.baidu.com
port:URI的端口号,比如80,指获得资源的窗口路径。
path、pathPrefix、pathPattern:表示路径信息
data匹配规则与action类似。
补充:在隐式启动时,可以先判断是否有activity能匹配我们的隐式Intent,方法如下:
Intent intent = new Intent();
intent.setAction("com.hfy.test.action");Intent.ACTION_CALL
intent.setDataAndType(Uri.parse("hfy://www.hfy.com"),"text/plain");
intent.addCategory(CATEGORY_DEFAULT);
ComponentName componentName = intent.resolveActivity(getPackageManager());
if (componentName != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
另外,