隐式启动Activity时,并没有在Intent中指明Acitivity所在的类,因此,Android系统一定存在某种匹配机制,使Android系统能够根据Intent中的数据信息,找到需要启动的Activity。这种匹配机制是依靠Android系统中的Intent过滤器(Intent Filter)来实现的。
Intent过滤器是一种根据Intent中的动作(action)、类别(category)和数据(data)等内容。对适合接收该 Intent 的组件进行匹配和筛选的机制。Intent过滤器可以匹配数据类型、路径和协议,还可以确定多个匹配项顺序的优先级(priority)。应用程序的Activity、Service和 BroadcastReceiver 组件都可以注册Intent过滤器。这样,这些组件在特定的数据格式上则可以产生相应的动作。
为了使组件能够注册Intent过滤器,通常在AndroidManifest.xml 文件的各个组件下定义 < intent-filter >节点,然后再< intent-filter >节点中声明该组件所支持的动作、执行的环境和数据格式等信息。当然,也可以在程序代码中动态的为组件设置Intent过滤器。< intent-filter >节点支持< action >标签 、 < category >标签 和 < data >标签,分别用来定义Intent过滤器的动作、类型和数据。 < intent-filter >节点支持的标签和属性说明如下图:
< intent-filter > 节点属性
标签 | 属性 | 说明 |
---|---|---|
action | android: name | 指定组件所能响应的动作 |
category | android: category | 指定以何种方式去服务Intent请求的动作 |
data | Android: host android: mimetype android: path android: port android: scheme | 指定一个有效的主机名 指定组件能处理的数据类型 有效的URI路径名 主键的有效端口号 所需要的特定协议 |
< category >标签用来指定Intent过滤器的服务方式,每个Intent过滤器可以定义多个< category >标签,我们可以使用自定义的类别,或者使用系统提供的类别。Android系统提供的类别可以参考下表:
值 | 说明 |
---|---|
ALTERNATIVE | Intent数据默认动作的一个可替换的执行方法 |
SELECTED_ALTERNATIVE | 和ALTERNATIVE类似,但替换的执行方法不是指定的,而是被解析出来的 |
BROWSABLE | 声明Activity可以由浏览器启动 |
DEFAULT | 为Intent过滤器中定义的数据提供默认动作 |
HOME | 设备启动后显示的第一个Activity |
LAUNCHER | 在应用程序启动时首先被显示 |
这种Intent 到 Intent 过滤器的映射过程称为“Intent解析”。Intent解析可以在所有的组件中,找到一个可以与请求的Intent达成最佳匹配的Intent过滤器。Android系统中Intent解析的匹配规则为:
- Android系统把所有应用程序包中的 Intent 过滤器集合在一起,形成一个完整的Intent过滤器列表。
- 在Intent与Intent过滤器进行匹配时,Android系统会将列表中所有Intent过滤器的“动作”和“类别”与Intent进行匹配,任何不匹配的Intent过滤器都将被过滤掉。没有指定“动作”的Intent过滤器可以匹配任何的Intent,但是没有指定“类别”的Intent过滤器只能匹配没有“类别”的Intent。
- 把Intent数据Uri的每个子部与Intent过滤器的< data >标签中的属性进行匹配,如果< data >标签指定了协议、主机名、路径名或MIME类型,那么这些属性都要与Intent的Uri数据部分进行匹配,任何不匹配的Intent过滤器均被过滤掉。
如果Intent过滤器的匹配结果多于一个,则可以根据在< intent-filter >标签中定义的优先级标签来对Intent过滤器进行排序,优先级最高的Intent过滤器将被选择。
IntentResolutionDemo示例说明了如何在AndroidManifest.xml文件中注册Intent过滤器,以及如何设置< intent - filter >节点属性来捕获指定的Intent。
AndroidManifest.xml的完整代码示例如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.satellitemenu">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MyActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
<data android:scheme="schemodemo" android:host="edu.hrbeu"/>
</intent-filter>
</activity>
</application>
</manifest>
第一个Activity 的 Intent 过滤器:
动作是android.intent.action.MAIN,类别是android.intent.category.LAUNCHER ,由此可知,这个Activity是应用程序启动后显示的默认用户界面。
第二个Activity的Intent过滤器
动作是android.intent.action.VIEW,表示根据Uri协议,以浏览的方式启动相应的Activity;类别是android.intent.category.DEFAULT ,表示数据的默认动作;数据的协议部分是:android:scheme="schemodemo",数据的主机名称部分是 android:host="edu.hrbeu"。
在MainActivity.java文件中,定义了一个Intent用来启动另一个Activity,这个Intent与Activity设置的过滤器是完全匹配的。相关代码如下:
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("schemodemo://edu.hrbeu/path"));
startActicity(intent);
代码中首先定义Intent,动作为Intent.ACTION_VIEW,与Intent过滤器的动作android.intent.action.VIEW匹配;Uri是shemodemo://edu.hrbeu/path,其中的协议部分为schemodemo,主机名为edu.hrbeu,也与Intent过滤器定义的数据要求完全匹配。因此代码中定义的Intent,在Android系统与Intent过滤器列表进行匹配时,会与AndroidManifest.xml文件中MyActivity定义的Intent过滤器完全匹配。