很多人对文档中的Intent和IntentFilter不理解是什么意思,我这里举例解释下。
Intent字面意思就是目标,目的。通俗一点,需要达成某些目标,则需要提供一些动作,这些目标的分类,以及达成这些目标所需要的一些数据等等。
Android中的Intent通过Action,Category和data等属性进行了相应的描述,我们想做某些事情(达成某些目标)
就需要填写这些参数的部分或全部,这样Android才会帮助我们自动的去进行某些操作。
IntentFilter是配合Intent而生的,你有目标行动或者结果,那么那些行动和结果就会有他完成的特定要求,
这些要求就是IntentFilter,可以理解为Intent和IntentFilter是相对应的。
隐式Intent的消息过滤器--IntentFilter
IntentFilter是用来解析隐式Intent(Implicit Intent)的,也就是说告诉系统你的组件(Activity, Service, BroadcastReceiver)
能够处理哪些隐式的Intent。在使用的时候我们通常是这样子的:
<receiver ...>
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<action android:name="android.intent.action.MEDIA_SHARED"/>
<action android:name="android.intent.action.MEDIA_REMOVED"/>
<action android:name="android.intent.action.MEDIA_EJECT"/>
<data android:scheme="file" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
<data android:scheme="package" />
</intent-filter>
</receiver>
</manifest>
在Manifest中使用IntentFilter时要注意以下三点:
1. 千万注意拼写错误
2. 要注意Data字段除了上面讨论的之外,对于IntentFilter还有另外的一点需要注意,就是对于某些Action是需要加上Data字段信息,否则有可能接收不到。
3. 同时也要注意Category字段,如果没有对IntentFilter写正确的Category字段,也是收不到Intent。
总之,对于Intent,要保证发出和接收完全一致,否则系统就无法找到相应的匹配,程序也就无法接收Intent。
另外要注意,尽量把Action进行合并写进一个IntentFilter中。因为对于每个IntentFilter标签都会创建一个IntentFilter对象,
所以如果写几个就会有几个对象在那,不但耗费资源而且在匹配的时候也会耗费更多的时间,
因为在查询匹配的时候是要一个IntentFilter对象接着一个IntentFilter对象进行检查的。直到找到最佳匹配或是到所有的IntentFilter都检查完为止。
IntentFilter的匹配规则
1. 通过Action字段来匹配这个是Intent中比较基本的一个字段,也比较简单,就是一个字串,
如果相等就匹配成功,否则证明还没找到目标。但要注意,如果IntentFilter没有指定Action,
那么它不会匹配到任何的隐式Intent,它只能被显式的Intent匹配上。反过来,如果Intent自己没有指定Action
,那么它能匹配上含有任何Action的IntentFilter,但不能匹配上没有指定Action的IntentFilter。
对于Action,平时要注意拼写错误,因为在AndroidManifest文件中声明Action都是字串,并且在编译时不会做检查,
运行时,如果Action拼错了导致匹配不上,要么是程序不能正常工作,要么会有异常抛出。
2. 通过Category字段来匹配对于Activity来讲,如果想处理隐式Intent,并且除了Intent.ACTION_MAIN以外,
必须指定Category为DEFAULT,否则不会被匹配到。因为Context.startActivity()和Context.startActivityForResult()会自动加上DEFAULT Category。
其他情况,Service和BroadcastReceiver则不会,对于Service和BroadcastReceiver,如果Intent中没有指定Category,那么在其IntentFilter中也不必指定。
Intent和IntentFilter对于组件Activity来讲注意事项比较多,但是对于Service和BroadcastReceiver来说就没有那么多的注意事项了,因为对于Service和BroadcastReceiver通常都不用设置Category和Data。但也有例外,比如前面所讲到的SD相关广播和应用程序安装相关广播。
另外要注意,如果使用Context.startActivity()或Context.startActivityForResult(),Context.bindService()和Context.startService(),如果系统没有为Intent匹配到目标Activity和Service那么会有RuntimeException(ActivityNotFoundException)抛出;如果有多个目标同时匹配,会以列表的方式来让用户选择使用哪个。
使用IntentFilter匹配来进行查询可用的组件
Intent和IntentFilter不但可以用来进行组件复用,还可以用于查询系统内都有哪里组件能做哪些事情。
比如Launcher上面会列出很多的应用,其实这种说法不准确,应该是上面列出了所有的能启动一个应用的组件
(比如,Dialer和Contacts同属于一个应用程序Contacts中,但是在Launcher里面却有二个,一个是Dialer一个是Contacts。那么Launcher是如何做到的呢?
它不可能是去检查系统文件,看看哪些应用程序文件存在,然后再列出来。它是通过查询Intent的方式,
把所有含有"android.intent.action.MAIN"和"android.intent.category. LAUNCHER"的Activity的相关信息都取出来,然后列出它们的名称和Icon。
同样,我们也可这样来获得具体相应特征的组件,具体的请参考SDK中的一篇文章(Resources->Articles->Can I Use this Intent?),讲的很详细,且有Sample Code。