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

来源:互联网 发布:网络麻将 编辑:程序博客网 时间:2024/05/22 06:16

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>

注意:

  1. 为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失败。一个过滤列表的action、category、data可以有多个,所有的action、category、data分别构成不同类别,同一个类别的信息共同约束当前类型的匹配过程。只有一个Intent**同时匹配**action,category,data类别才算完全匹配
  2. 一个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/etchttp://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,意义在于只要返回值不为null,那么startActivity一定可以成功 ;
如果不用,就可以把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同样提供了类似的方法去获取成功匹配的组件信息

0 0
原创粉丝点击