Intent匹配规则

通过Intent启动Activity有“显示启动”和“隐式启动”两种方式。显示启动需要明确指定被启动Activity的组件信息,包括包名和类名;而隐式启动不需要明确指定启动哪个Activity,只需要使用“匹配规则”描述要启动的Activity的一些特征,系统会根据这些特征搜索对应的Activity,如果对应的Activity有多个,会让用户选择要启动的Activity,否则,直接启动匹配到的Activity。

隐式启动通常用于APP之间的交互,比如,一个APP要播放音乐,但是该APP没有提供播放功能,这时该APP就可以通过隐式启动,调用当前系统中能够播放音乐的APP进行播放。下面介绍隐式启动的使用及其匹配规则。

隐式启动

隐式启动需要Intent能够匹配目标组件在intent-filter标签中设置的过滤信息,intent-filter标签中能设置的过滤信息有action、category和data三类,下面是一个过滤规则的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<activity
android:name="com.chinaums.opensdkdemo.activity.tab.MyTabActivity"
android:configChanges="keyboardHidden|orientation"
android:launchMode="singleTask"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<!-- umsapp://main.app/openwith?key1=value1&key2=value2... -->
<data
android:host="main.app"
android:pathPrefix="/openwith"
android:scheme="umsapp" />
</intent-filter>
</activity>

系统对Intent进行匹配时,要同时匹配以上三类信息,才能启动目标组件。intent-filter标签中的action、category和data可以有多个,同时,一个Activity中也可以有多个intent-filter。不过,一个Intent只要匹配任何一组intent-filter即可启动对应的的Activity。

匹配规则

接下来详细分析action、category和data这三类信息的匹配规则。

action匹配规则

action是一个字符串,系统预定了一些action,可以直接使用,同时,也可以自定义action。

action的匹配规则要求Intent中的action存在,并且必须和intent-filter标签中的一个action相同。

需要注意的是action区分大小写。

category匹配规则

category也是一个字符串,系统也预定义了一些category,同样,也可以自定义category。

但是,category匹配规则与action不一样。category匹配规则要求,如果Intent中出现了category,不管有几个category,对于每个category,它必须是intent-filter标签中已经定义了的category。

需要注意的是,如果Intent没有定义category,系统在调用startActivity()和startActivityForResult()方式时,会默认为Intent加上 “android.intent.category.DEFAULT” 这个category。因此,要想Activity能够接收隐式调用,必须在其intent-filter标签中指定这个默认的category。

data匹配规则

data匹配规则和action类似,如果intent-filter标签中定义了data,那么Intent中必须要也要定义可匹配的data。

data语法格式如下所示:

1
2
3
4
5
6
7
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string" />

data由两部分组成:mimeType和URI。

mimeType指媒体类型,比如image/jpeg、audio/mpeg4-generic等,可以表示图片、文本、视频等不同的媒体格式。

URI包含了data标签中,除了mimeType以外的所有属性,下面是URI的结构及其实例:

1
2
3
4
<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]

content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com/search/info

URI中每项数据的含义如下:

  • scheme:URI的模式,例如http、file、content等,如果URI中没有指定scheme,那么URI无效的。
  • host:URI的主机名,例如www.baidu.com,如果host没有指定,URI也是无效的。
  • port:URI的端口号,只有指定scheme和host参数,port参数才有意义。
  • path:表示URI的路径信息。
  • pathPrefix:表示URI路径的前缀信息。
  • pathPattern:也可以表示路径信息,不过可以包含通配符 “*” ,用于表示0个或多个任意字符。

下面介绍两个data匹配的实例。

只配置mimeType

1
2
3
4
<intent-filter>
<data android:mimeType="image/*" />
...
</intent-filter>

上面的规则指定了媒体类型为所有格式的图片类型,那么Intent中的mimeType必须指定为 “image/*” 才能匹配。这里intent-filter没有指定URI,但是系统会为其指定默认值为content和file,所以,要匹配这个过滤器,Intent中URI部分的schema还必须设置为content或者file。

因此,要匹配上面的规则,可以使用下面的示例代码:

1
intent.setDataAndType(Uri.parse("file://abc"), "image/png");

配置多个data

1
2
3
4
5
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
...
</intent-filter>

上面的规则指定了两组data规则,如果要匹配这个规则,可以使用以下示例代码:

1
intent.setDataAndType(Uri.parse("file://abc"), "video/mpeg");

或者

1
intent.setDataAndType(Uri.parse("file://abc"), "audio/mpeg");

匹配规则检测

在用隐式Intent启动一个Activity的时候,可以使用resolveActivity()方法对匹配规则进行检测,如果返为null就表示该Intent无法匹配到任何Activity。

还可以使用queryIntentActivities()方法进行检测,不过,这个方法返回所有成功匹配的Activity信息,而resolveActivity()方法返回的是最佳匹配的Activity信息。

另外,Intent的匹配规则对于Service和BroadcastReceiver也是一样的,不过Android建议尽量使用显示的方式启动Service。同时,PackageManager对象也提供了类似方法去检测是否存在匹配的Service或BroadcastReceiver组件。

坚持原创技术分享,您的支持将鼓励我继续创作!