Android IntentFilter 匹配原则浅析

1
Intent
分为两大类,显式和隐式。


显式事件,就是指通过
component
Name

属性,明确指定了目标组件的事件。


比如我们新建一个
Intent,指名道姓的说,此事件用于启动名为“com.silenceburn.XXXX”的Activity,那么这就是一个显式事件。


隐式事件,就是指没有
component
Name

属性,没有明确指定目标组件的事件。


比如系统向所有监控通话情况的程序发送的“来电话了!”的事件,由于系统不确定谁会处理这个事件,因此系统不会明确指定目标组件,也就是说没有目标组件,那么这就是个隐式的事件。


此处只是简介显式和隐式事件,更精确详细的描述请查阅
SDK文档,我们只需要记住一点,两种事件的最大区别是
component Name

属性是否为空。

 

2

事件过滤策略

IntentFilter


系统在传送显式事件时非常方便,因为如果把
Intent比作一封信,那么component Name就是一个详细的收件人地址,系统可以精确的把显式事件送达目标组件。

 


而传送隐式事件时,就比较麻烦了。因为这封信的信封上,没有写收信地址!


那怎么办呢?系统做了一个艰难的决定,就是把信拆开看看。通过信件内容里面的线索,去寻找合适的收件人。


比如信中的线索描述到:“收信人是男性,快
30岁了,未婚,喜欢玩游戏”,那么系统就在小区里面去找这样的人。

 


非常值得庆幸的事情是,这个小区的人素质非常高,每户人家都写了点自我介绍在门口,


比如张三写道:“我是男性,
90后,未婚,喜欢玩游戏”,李四写道:“我是女性,快30岁了,未婚,喜欢逛街”等等等等。


有了每户人家的自我介绍,系统就能很快的定位真正的收件人了!

 


上面是一个类比的例子,不过
android系统处理隐式事件的策略,基本上就是上述这种模式了。

 


首先系统会通过观察
Intent的内容(打开信件看内容),取得匹配线索,系统所需的线索是如下三种

 action

 data (both URI and
data type)

 category

 


其次,系统中每个组件,如果想收取隐式事件,则必须声明自己的
IntentFilter(自我介绍,我对什么样的信件感兴趣)。


至于怎么写
IntentFilter,已经相当明了了,那就是应该是这样写:

我是组件XXXX,我想要接收这样的隐式事件:它的ACTION必须是
XXX,它的
category
必须是
YYYY

,它包含的
data必须是ZZZZ “


如果组件不声明
IntentFilter,那么所有的隐式事件都不会发送给该组件。(注意,这并不影响向该组件发送显式事件。)

 


对于系统中发生的每个隐式事件,系统都会尝试将
action, data , category
和系统中各个组件声明的
IntentFilter
去进行匹配,以找到合适的接收者。

3.IntentFilter匹配原则


对于显式事件,系统可以精确送达。对于隐式事件,系统分析事件的
action, data , category
内容,并和各个组件声明的
IntentFilter进行匹配,找出匹配的组件进行送达。actioncategory没什么好说的,再此我将最复杂的data匹配展开来进行描述一下:


首先务必认识到,
data是一个相对复杂的要素。

dataURI来描述和定位,URI由三部分组成,

scheme://host:port/path     

模式
://
主机:端口/路径


此外在事件中,还可以设置
dataMIME类型,作为事件的datatype属性。为了描述方便,下文将IntentFilter简写为filter,请大家注意。


首先明确一个匹配原则,就是对于
URI的匹配,只比较filter中声明的部分。


部分匹配原则:只要
filter中声明的部分匹配成功,就认为整个URI匹配成功。


举例来说,
    content://com.silenceburn.SdCardTester:1000/mydata/private/


filter定义为 
content://com.silenceburn.SdCardTester:1000/    


是可以匹配的。


注意
filter中并没有定义path部分,但是依然可以匹配成功,因为filter不声明的部分不进行比较。


换句话讲,任何符合
content://com.silenceburn.SdCardTester:1000/的事件,无论path是什么,都可以匹配成功。


接下来是真正的
data部分的,也就是URI的匹配规则如下:

1.

如果
dataURIdatatype为空,则
filter
URItype也必须为空,才能匹配成功

2.

如果
dataURI不为空,但是datatype为空,则
filter
必须定义
URI并匹配成功,且type为空,才能匹配成功

3.

如果
dataURI为空,但是datatype不为空,则
filter
必须
URI为空,定义type并匹配成功,才能匹配成功

4.

如果
dataURIdata都不为空,则
filter
URItype都必须定义并匹配成功,才能匹配成功。对于URI部分,有一个特殊处理,就是即使filter没有定义URIcontentfile两种URI也作为既存的URI存在。

 


通过上文的描述,大家就可以明白为什么在注册
SD卡插拔接收器时,不但需要

IntentFilter intentFilter = new
IntentFilter(Intent.ACTION_MEDIA_MOUNTED);

             
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);

             
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);

             
intentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);

             
intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);

             
intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);


而且需要添加

      
intentFilter.addDataScheme(“file”);


注册应用安装卸载事件时不但需要

      
IntentFilter intentFilter = new IntentFilter();

             
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);

             
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);

             
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);


而且需要

      
intentFilter.addDataScheme(“package”);


原因就在
Data的匹配。


最后,该文章是经过我在互联网中,某个文章中提取和加工而来,首先感谢原作者的精心设计,原文地址如下:
http://blog.csdn.net/silenceburn/article/details/6083375