您的位置:首页 > 其它

开发艺术探索阅读-IntnetFilter的匹配规则

2016-04-24 00:43 260 查看

1.3 IntentFilter的匹配规则

启动activity分为两种:

1. 显示调用

2. 隐式调用

隐式调用需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标activity

IntentFilter中的过滤信息有action、category、data

<activity
android:name = "xxx.xxx.xxx"
android:label = "xxx"
android:launchMode = "singleTask"
android:taskAffinity = "com.xxx.task1">
<intent-filter>
<action android:name = "com.xxx.charpter_1.c"/>
<action android:name = "com.xxx.charpter_1.d"/>
<category android:name = "con.xxx.category.c"/>
<data android:mimeType = "text/plain"
</intent-filter>
</activity>


注意:

为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失败。一个过滤列表的action、category、data可以有多个,所有的action、category、data分别构成不同类别,同一个类别的信息共同约束当前类型的匹配过程。只有一个Intent**同时匹配**action,category,data类别才算完全匹配

一个activity可以有多个Intent-filter,一个intent只需要匹配上其中一组就可以启动对应的activity

各项属性的匹配规则

1.action的匹配规则

action是一个字符串,系统预先定义了一些action,同时我们也可以在应用中定义自己的action

Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功

Intent中如果没有指定action,那么匹配失败,action的匹配要求Intent中的action必须存在

action区分大小写,大小写不同字符串相同的action会匹配失败

2.category的匹配规则

category是一个字符串,系统预定义了一些category,同时我们也可以在应用中定义自己的category

与action匹配规则不同的是,如果在Intent中定义了多个category,那么每一个都必须和IntentFilter中的category中的一个相同,如果Intent中没有category,按照上面的描述,这个Intent仍然可以匹配成功

为什么不设置category系统也可以匹配上呢?

系统调用startActivity的时候或者startActivityResult的时候会默认为Intent加上”android.intent,DEFAULT”这个category,同时,为了我们的activity能够接受隐式调用,必须在intent-filter中指定”android.intent.category.DEFAULT”

3.data的匹配规则

data的匹配规则和action类似,如果定义了data,那么Intent必须也要定义可匹配的data,在介绍data的匹配规则之前,我们需要先了解一下data的结构,因为data稍微有点复杂.

<data android:scheme = "string"
android:host = "string"
android:port = "string"
android:path = "string"
android:pathPattern = "string"
android:pathPrefix = "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的模式,比如file、http、content等,如果URI中没有指定scheme,那么整个URI的其他参数无效,这也意味着URI是无效的

Host : URI的主机名,比如www.baidu.com,如果host未指定,那么整个URI中的其他参数都无效,这也意味着URI是无效的

Port : URI的端口号,比如80,仅当URI中指定了scheme和host参数的时候,port参数才有意义

path、pathPattern、pathPrefix : 这三个参数表述路径信息:

1. path表示完整的路径

2. pathPattern也表示完整的路径信息名单是它里面可以包含通配符” * “,*表示0个或者多个任意字符,需要注意的是由于正则表达式,想表达出真是的字符串,

那么"*"要写成\\*
"\"要写成"\\\\"


3. pathPrefix表示路径的前缀信息

<1>这种过滤规则

<intent-filter>
<data android:mieType = "image/*"/>
</intent-filter>


这种过滤规则制定了媒体类型为所有类型的图片,那么Intent中的mimeType属性必须为”image/*”才能匹配

这种情况下虽然没有指定URI,但是却有默认值,默认值为contnet和file

也就是说,虽然没有指定URI,但是Intent的URI部分的scheme必须为content或者file才能匹配

为了匹配<1>中的必须写成

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


另外,如果要为Intent指定完成的data,必须要调用setDataAndType方法,不能先调用setData再调用setType方法,因为这两个方法会清除对方的值,这个看源码就很容易会理解

setData会把mimeType置为null,同理setType也会把URI置为null

<2>如下过滤规则

<intent-filter>
<data android:mimeType = "video/mpeg" android:scheme = "http".../>
<data android:mimeType = "audio/mpeg" android:scheme = "http".../>
</intent-filter>


我们可以写出如下示例

intent.setDataAndType(Uri.parse("http://abc"),"video/mpeg")


或者

intent.setDataAndType(Uri.parse("http://abc"),"audio/mpeg")


data的两种写法,作用一样,

<Intent-filter...><data android:scheme = "file" android:host = "www.baidu.com"/>
</Intent-filter>
<intent-filter...>
<data android:scheme = "file"/>
<data android:host = "www.baicu.com"/>
</intent-filter...>


现在我们给出完全匹配它的Intent

Intent intent = new Intent("com.ryg.charpter_1.c");
intent.addCategory("com.ryg.category.c");
intent.setDataAndType(Uri.parse("file://abc"),"text/plain");
startActivity(intent);


Intent-filter的匹配规则对于Service和BroadcastReceiver也是同样的道理,不过系统对于service的建议是尽量使用显式调用方式来启动服务

我们通过隐式调用启动一个activity的时候,可以先做一下判断,看是否有activity匹配我们的activity,一般方法有两种

1. 采用packagemanagerresolveActivity方法或者IntentresolveActivity方法,如果他们找不到匹配的activity就会返回null,我们通过判断返回值就可以规避错误

2. packageManager还提供了queryIntentActivities方法,这个方法和resolveActivity方法不同的是:它不是返回最佳匹配的activity信息而是返回所有成功匹配的activcity信息

public abstract List<ResolveInfo> queryIntentActivitied(Intent intent,int flags)
public abstract ResolveInfo resolveActivity(Intent intent,int flags);


上述两个方法的第一个参数比较好理解,第二个参数需要注意,我们需使MATCH_DEFAULT_ONLY这个标记位,这个标记位的含义是仅仅匹配那些在intent-filter中声明这个category的Activity,意义在于[b]只要返回值不为null,那么startActivity一定可以成功 ;[/b]

如果不用,就可以把intent-filter中category不含DEFAULT的那些activity匹配出来,从而导致startactivity可能失败。因此,不含有DEFAULT这个category的activity是无法接受隐式Intent,在action和category中,有一类action和category是比较重要的他们是

<action android:name = "android.intent.action.MAIN"/>
<action android:name = "android.intent.category.LAUNCHER"/>


这两者共同作用是表明这是一个入口activity,并且会出现在系统的应用列表中,少了任何一个都没有实际意义,也无法出现在系统的应用列表

针对Service和BroadCastReceiver,packageManager同样提供了类似的方法去获取成功匹配的组件信息
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: