最近学习《Android开发艺术探索》中的IntentFiler部分,获益良多。以前项目中使用显式启动为多,很多时候看到隐式启动的category配置时都有点摸不着头脑,这下完全清晰了,在这里做下笔记,以备查询。
IntentFilter的作用
用于规定组件隐式启动时的匹配规则。规定了在隐式调用时,什么样的Intent能够启动设置了这个IntentFilter的组件。
IntentFilter的组成
IntentFilter包含3种类型的匹配项,Intent只有同时满足3个匹配项,才能启动该组件
Action
action是一个字符串,一个Intent只要action和IntentFilter中定义的action中的一个完全一致,就可以匹配成功。Action区分大小写
Category
['kætəɡɔːri]
category同样是一个字符串,它和action的区别在于,如果Intent包含了category,那么它所包含的所有category,都必须在IntentFilter找到完全一样的category,才算匹配成功。
另外,由于系统在调用startActivity和startActivityForResult时,会默认为Intent添加上"android.intent.category.DEFAULT"这个category,所以当我们的IntentFilter设置了这个category时,Intent即使不设置任何category,也能匹配成功。
Data
data用于规定,在启动对应组件时,Intent必须传递过来的资源的Uri和资源类型,例如,如果我们要启动一个用于操作缩放图片的activity,必须在Data中传递过来一张图片的地址。data和action一样,只要Intent中的data能够匹配到IntentFilter中的其中一个data,即算是匹配成功。
data的结构如下:
<dataandroid:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathprefix="string"
android:minetype="string"/>
data的内容包合2个部分,资源Uri的限制和资源的类型
Uri的结构如下:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
Uri的具体例子
Content://com.example.project:200/folder/etc
http://www.baidu.com:80/search/info
Scheme
Uri的模式,例如http、file、content等,如果URI中没有指定scheme,那个整个URI的其他参数都无效,URI是无效的
Host
Uri的主机名,例如www.baidu.com、192.168.1.1等,如果host未指定,那么URI的其他参数和URI本身,都是无效的
Port
uri的端口号,例如8080,只有uri指定了scheme和host,port才有效
Path、pathPattern、pathPrefix
path表示完整的路径信息。pathPattern也表示路径信息,但它可以通过*来表示0个或多个任意字符。这使得IntentFiler匹配的路径更加灵活。同时,由于正则表达式的规范,要表示真正的*和/,则需要写成"//*"和""。pathPrefix表示路径的前缀信息
例如:
<intent-filter>
<data android:mimeType="image/*"/>
…
</intent-filter>
这个过滤规则规定,Intent必须传递任意类型的图片。这种情况下虽然没有指定URI,但却有默认值为content和File。即是说,为了匹配这个Filter,Intent中Uri部分scheme必须为content或者file才能匹配。
匹配的Intent例子如下:
Intent.setDataAndType(Uri.parse("file://data/data/com.example.project/a.png"),"image/png").
Intent要设置完整的Data,必须调用setDataAndType方法,不能通过先调用setData再调用setType方法,因为后2个方法会互相清空对方的值
另外,和action不同的是,以下2种方式设置的data,起同样的效果
<intent-filter…>
<data android:scheme="file"android:host="www.baidu.com"/>
…
</intent-filter>
<intent-filter…>
<data android:scheme="file"/>
<data android:host="www.baidu.com">
…
</intent-filter>
IntentFilter的匹配规则对应Service和BroadcastReceiver也是同样的道理,不过系统对应Service的建议是尽量使用显示调用来启动服务
检测Intent是否匹配成功
为了避免隐式启动Activity时因找不到匹配的activity而报错,应该先检查是否匹配成功。方法有2种:
1.PackageManager的方法:public abstract ResolveInfo resolveActivity(Intent intent,intflags)
2.Intent的方法:public abstract List<ResolveInfo> queryIntentActivities(Intent intent,int flags)
上述2个方法中的第二个参数,我们要使用MATCH_DEFAULT_ONLY,它的含义是只匹配包合"android.intent.category.DEFAULT"这个category的activity。如果不使用这个标记位,可能会导致startActivity失败,因为不包含DEFAULT这个category的activity是无法接收隐式Intent的。
另外,针对Service和BroadcastReceiver,PackageManager同样提供了类似的方法去获取成功匹配的组件信息