Activity LaunchMode,TaskAffinity,intent过滤规则及Flag资料整理

转转请注明出处:http://blog.csdn.net/u011510784/article/details/50856323

Activity LaunchMode,TaskAffinity及Flag相关资料详细整理.


一.Activity的LaunchMode


(1) standard:标准模式,也是系统默认模式,每次启动一个Activity都会重建一个新的实例,不管这个Activity是否已经存在.这种模式下,一个任务栈可以有多个实例,每个实例也可以属于不同的任务栈,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中.但是如果是非Activity的context启动它时,会报错,需要为待启动的Activity添加FLAG_ACTIVITY_NEW_TASK标记.这时,待启动的Activity实际上是以singleTask模式启动的.


(2)singleTop:栈顶复用模式.这种模式下,如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息.这个Activity的onCreate,onStart不会被系统调用.如果新Activity的实例已存在但是不是位于栈顶,那么这个新Activity仍会被重新创建.


(3)singleTask:栈内复用模式.在一个任务栈中,只要目标Activity的实例存在,那么多次启动此Activity都不会重新创建实例,系统会调用存在的那个Activity实例的onNewIntent方法.同时singleTask模式默认具有clearTop的效果,如果当前任务栈的情况为ABCD(表示Activity实例),用这个模式启动B,那么会导致栈内所有在B上面的Activity全部出栈,于是此任务栈中的情况变为AB.


(4)singleInstance:单实例模式.具有此模式的Activity只能单独的位于一个任务栈中,如果 Activity A是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求都不会创建新的实例,除非这个独特的栈被系统销毁了.


有两种方法可以指定Activity的启动模式,第一种是通过AndroidMenifest指定,另一种是通过Intent中设置标志来指定.区别是第二种的优先级高于第一种,其次是这两种方式的限定范围不同,比如第一种无法为Activity指定FLAG_ACTIVITY_CLEAR_TOP标志,二第二种方法无法为Activity指定singleInstance模式.


二.Activity的TaskAffinity

TaskAffinity可以翻译为任务相关性,这个参数标识了一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名,我们可以为每个Activity单独指定TaskAffinity属性,这个属性值不能和包名相同,否则相当于没有指定.TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,其他情况下没有意义.


1.当TaskAffinity和singleTask启动模式配对使用时,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中.


2.当TaskAffinity和allowTaskReparenting结合使用时.举个例子,当应用A启动应用B的某个Activity后,如果这个 Activity的allowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中.比如应用A启动了应用B的一个Activity C,然后按home键回到桌面,然后在单击应用B的桌面图标,这时启动的不是应用B的主Activity,而是Activity C,或者说C从应用A的任务栈转移到了应用B的任务栈.可以这么理解由于应用A启动了Activity C,这时C只能运行在A的任务栈中,但是C属于应用B,并且C的TaskAffinity值为应用B的包名,所以当B启动后,B会创建自己的任务栈,这时系统发现C所需要的任务栈被创建了,所以把C从A的任务栈转移到了B的任务栈.


现在看一个例子:假设在一个应用中有三个Activity,分别是MainActivity A, SecondActivity B, 和ThirdActivity C .我们将B和C设置成singleTask并指定它们的TaskAffinity属性为"com.test.mytask",这个属性值为字符串,并且中间必须含有包名分隔符"." ,然后打开应用,进入A,在A中启动B,在B中启动C,在C中启动A,最后在A中启动B,现在按2次back键,会看到哪个Activity呢?答案是回到了桌面,下面分析一下:

A没有指定任何模式和属性,所以它是standard模式,A的TaskAffinity属性值是默认值即应用的包名,我们设置了B和C为singleTask模式,并且具有相同的TaskAffinity值"com.test.mytask".当A启动B时,会为B创建一个新的名为"com.test.mytask"的栈,B启动C时,由于C所需要的任务栈已经创建了,所以C的实例会直接进入B所在的那个栈,接着C在启动A,A是standard模式,所以A会创建一个新的实例并添加到启动它的那个Activity所在的栈中,即名为"com.test.mytask"的这个栈.这时存在两个A的实例,一个在名为应用包名的任务栈中,另一个在名为"com.test.mytask"的任务栈中,现在名字为包名的任务栈里面只有一个A,我们指定的"com.test.mytask"这个栈,里面的Activity为BCA,接下来A再启动B,由于B是singleTask模式,B需要回到栈顶,那么它上面的Activity都会出栈,这时这个栈中只存在一个Activity B,然后按back键,B出栈,B所在的任务栈不存在,这时回到后台任务栈,并把A显示出来,接着再按back,回到桌面.


三.IntentFilter的匹配规则.

启动Activity分为两种方式,显示调用和隐式调用.显示调用需要明确的指定被启动对象的组件信息,包括包名和类名.隐式调用需要intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标Activity. IntentFilter中的过滤信息有action,category,data,需要同时匹配过滤列表中的action,category,data信息,否则匹配失败.一个过滤列表中的action,category和data可以有多个,所有的action,category,data分别构成不同类别,同一类别中的信息共同约束当前类别的匹配过程.只有一个intent同时匹配action类别,category类别,data类别才算完全匹配,否则启动不了目标Activity.另外,一个Activity中可以有多个intent-filter,一个intent只要能匹配任何一组intent-filter即可成功启动对应的Activity.如:

<span style="font-family:Comic Sans MS;font-size:14px;"><span style="font-family:Comic Sans MS;font-size:14px;">       <activity android:name="com.jiaxu.TestActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEND"/>
                <action android:name="android.intent.action.SEND_MULTIPLE"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="text/plain"/>
                <data android:mimeType="image/*"/>
                <data android:mimeType="video/*"/>
            </intent-filter>
            
            <intent-filter>
                <action android:name="android.intent.action.SEND"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="text/plain"/>
            </intent-filter>
        </activity></span></span>

下面分析各个属性的匹配规则.

1.action的匹配规则:

action是一个字符串,系统定义了一些action,我们也可以定义自己的action. action的匹配规则是intent中任何一个action的值能够和过滤规则中任何一个action的值完全相同,那么匹配成功.但是如果过滤规则中指定了action,intent中没有设置action那么匹配失败,另外action是区分大小写的.


2.category的匹配规则:

category是一个字符串,系统定义了一些category,我们也可以定义自己的category. category的匹配规则是intent中所有的category都必须和过滤规则中的其中某个category相同,但是intent中可以不指定category,因为系统在调用startActivity或者startActivityForResult的时候会默认为intent加上"android.intent.category.DEFAULT"这个category,所以这就要求我们必须在intent_filter中指定"android.intent.category.DEFAULT"这个category.


3.data的匹配规则和action类似,如果过滤规则中定义了data,那么intent中必须也要定义可匹配的data,只要匹配规律规则中的任意一个即可.

data的属性结构如下:

<data android:host="String"
      android:mimeType="String"
      android:path="String"
      android:pathPattern="String"
      android:pathPrefix="String"
      android:port="String"
      android:scheme="String"/>
data由两部分组成,mimeType和URI. mimeType指媒体类型,比如image/jpeg,audio/mpeg4-generic,video/* 等等,可以表示图片,文本,视频等不同的媒体格式,URI中数据较多,结构如下:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

具体例子如下:

content://com.example.project:200/folder/subfolder/etc

http://www.baidu.com:80/search/info

下面看一下每个属性的含义;

Scheme:URI的模式,比如http,file,content等,如果URI中没有指定scheme,那么整个URI无效.

Host:URI的主机名,比如www.baidu.com,如果URI没有指定host,那么整个URI无效.

Port:URI中的端口号,比如80.

Path,pathPattern和pathPrefix:这三个参数表示路径信息,其中path表示完整的路径信息:pathPattern也可以表示完整的路径信息,但是它里面可以包含通配符"*","*"表示0个或者多个任意字符,需要注意,由于正则表达式的规范,如果想表示真实的字符串,那么"*"要写成"\\*",\"要写成"\\\\",pathPrefix表示路径的前缀信息.如下一个例子:

  <intent-filter>
     <data android:mimeType="image/*"/>
         ......
  </intent-filter>
这个规则指定了媒体类型为所有类型的图片,intent中data的mimeType属性为"image/*"才可以匹配, 过滤规则中没有指定URI,但是却有默认值URI的默认值为content和file,也就是说,虽然没有指定URI,但是Intent中data的URI中的的scheme部分必须写成content或者file才可以匹配,否则启动不了这个Activity:

intent.setDataAndType(Uri.parse("file://abc"),"image/png").

intent指定data时,需要调用setDataAndType方法,不能分开调用setData,setType这两个方法,因为这两个方法会互相清空对方的值.
当我们通过隐式方式启动一个Activity时,需要做一下判断,看看是否有Activity可以匹配我们指定的intent,判断方法可以使用PackageManageer的resolveActivity方法,queryIntentActivities方法,或者Intent的resolveActivity方法.

需要注意:

public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
            int flags);
在这个方法中,第二个参数,我们要使用MATCH_DEFAULT_ONLY这个标记,它的含义是只匹配那些在intent-filter中声明了<category android:name="android.intent.category.DEFAULT"/>这个category的Activity.这样可以把intent-filter中category不含DEFAULT的那些Activity过滤掉,避免启动失败.在action和category中,有一个是我们常见也是很重的:

  <intent-filter>
         <action android:name="android.intent.action.MAIN"/>
         <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
两者共同标明这是一个入口Activity,并且会出现在系统的应用列表中.


四 Intet的FLAG.

FLAG属性较多,详情见:http://blog.csdn.net/u011510784/article/details/51003732





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)` 是用于设置 Intent 的标志,指示在启动活动时创建一个新的任务。 通过设置该标志,您可以在一个新的任务中启动活动,而不是将其添加到当前任务的堆栈中。这意味着新活动将在一个新的任务栈中打开,并成为该任务的根活动。 这种情况通常发生在以下情况下: 1. 在非活动上下文中启动活动:例如,在服务、广播接收器或应用程序的后台任务中启动活动时,由于缺乏 UI 上下文,您需要设置 `FLAG_ACTIVITY_NEW_TASK` 标志来创建一个新的任务,以便启动活动。 2. 启动独立的任务:有时,您可能希望将某个活动作为一个单独的任务打开,而不是与当前应用程序的任务关联。通过设置 `FLAG_ACTIVITY_NEW_TASK` 标志,您可以实现这一点。 下面是一个示例代码片段,演示如何使用 `intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)` 启动一个新的任务: ```java Intent intent = new Intent(context, YourActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); ``` 在此示例中,我们创建了一个 Intent 对象,指定目标活动为 `YourActivity`。然后,我们使用 `setFlags()` 方法设置 `FLAG_ACTIVITY_NEW_TASK` 标志。最后,我们使用 `startActivity()` 方法启动活动。 请注意,使用 `FLAG_ACTIVITY_NEW_TASK` 标志启动活动时,您需要确保目标活动在 AndroidManifest.xml 文件中被声明为具有 `android:launchMode="standard"` 或 `android:launchMode="singleTask"` 属性,以便正确处理任务和活动的创建和销毁。 如果您有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值