Android开发-API指南-Intent和Intent过滤器

时间:2022-05-24 03:09:06

Intents and Intent Filters

英文原文:http://developer.android.com/guide/components/intents-filters.html
采集(更新)日期:2014-7-10
搬迁自原博客:http://blog.sina.com.cn/s/blog_48d491300102uxxw.html

Intent
就是一个消息对象,用于向其他
应用程序组件
发送 Action 请求。
虽然用 Intent 实现组件间通讯的方式多种多样,但只有三种基本的使用场景:

  • 启动 Activity :

    在应用程序中,一个 Activity 代表着一个屏幕窗口。
    通过向
    startActivity()
    传入一个
    Intent,可以启动一个 Activity 实例。
    这个 Intent 对需要启动的 Activity 进行了说明,并可附带任何必要的数据。

    如果需要在 Activity 结束时从中接收结果,请调用
    startActivityForResult()来启动。
    这样在 Activity 的回调方法
    onActivityResult()
    中就会接收到另一个作为结果返回的
    Intent对象。
    更多信息请参阅Activity指南。

  • 启动服务:

    Service
    是一种在后台执行操作的组件,它没有用户界面。
    通过向
    startService()
    传入一个
    Intent
    可以启动一个服务来完成一件一次性的操作(比如下载一个文件)。
    在这个Intent
    中对需要启动的服务进行了说明,并可附带任何必要的数据。

    如果服务设计为 C/S 模式,你可以将其他组件与该服务绑定,这通过向
    bindService()
    传入一个
    Intent
    来实现。
    详情请参阅服务指南。

  • 发布广播:

    广播是一种可以被任何应用程序接收的消息。
    系统为系统事件发布各种各样的广播消息,比如系统启动、设备开始充电等。
    通过向
    sendBroadcast()
    sendOrderedBroadcast()
    sendStickyBroadcast()
    传入一个
    Intent
    ,就可以向其他应用程序发送一条广播。

Intent 种类


Intent 有两种类型:

  • 显式 Intent用名称(完全限定类名)来指定需要启动的组件。
    显式 Intent 的典型用途就是用来启动应用程序内部的组件,因为需要启动的 Activity 或服务的类名是已知的。
    例如,启动一个 Activity 来响应用户的 Action,或者启动一个服务在后台下载某个文件。
  • 隐式 Intent不用指定组件的名称,而是声明一个需要执行的通用 Action,
    其他应用程序的组件可以来处理这个 Action。
    例如,如果需要向用户展示一个地图上的位置,就可以用一个隐式 Intent 来请求其他某个有能力显示地图的应用程序来完成。

如果是为了启动 Activity 或服务,在创建显式 Intent 时,系统会立即启动
Intent
中指定的应用程序组件。

Android开发-API指南-Intent和Intent过滤器

图 1.
隐式 Intent 在系统中传递并启动另一个 Activity 的过程图解:
[1] Activity A 创建了一个附带 Action 信息的
Intent
,并把它传入
startActivity()
[2] Android 系统检索所有应用程序,查找符合该 Intent 的 Intent 过滤器。
一旦找到匹配的 Activity,
[3] 系统就通过调用其
onCreate()
来启动它(Activity B),并且将该
Intent
作为参数传入。

隐式 Intent 一经创建, Android 系统就会找到需要启动的相应组件,
这通过将 Intent 的内容和当前设备上其他应用程序的
Manifest 文件
中声明的Intent 过滤器进行比较来完成。
如果存在多个可兼容的 Intent 过滤器,系统会显示一个对话框,用户可以从中选取一个应用程序来执行。

Intent 过滤器是一个位于 Manifest 文件中的表达式,它定义了当前组件愿意接收的 Intent 的种类。
例如,可以为 Activity 声明一个 Intent 过滤器,这样其他应用程序就可以通过某类 Intent 直接启动这个 Activity。
可想而知,如果没有为 Activity 声明任何 Intent 过滤器,则它就只能通过显式 Intent 来启动了。

提醒:
为了确保应用程序的安全性,请一定使用显式 Intent 来启动
Service
,并且不为服务声明 Intent 过滤器。
使用隐式 Intent 启动服务是存在安全风险的,因为无法确定是由哪个服务来响应 Intent,
用户也无法知道启动了哪个服务。

创建 Intent


Intent
对象中包含了 Android 系统用于确定该启动哪个组件的信息,比如组件的确切名称或者应该接收该 Intent 的组件类型,
再加上接收方组件为了执行操作需要用到的信息(比如要执行的 Action 及要操作的数据)。

Intent
中的信息主要包括:

组件名称
需要启动的组件名称。

这是可选项,但对于创建显式 Intent 而言,这是必填项,也就意味着 Intent 只能传递给由本组件名称指定的应用程序组件。
如果没有给出组件名称,则此 Intent 就是隐式 Intent,
系统会根据 Intent 中的其他信息(比如下述的 action、data 和 category)决定由哪个组件来接收 Intent 。
因此,如果需要启动应用程序内部的某个组件,就应该定义组件名称。

注意:
如果要启动
Service
务必指定组件的名称
否则就无法确定由哪个服务来响应 Intent ,用户也无法知道启动了哪个服务。

Intent
中的这个字段是一个
ComponentName
对象,这里可以使用目标组件的完全限定类名,类名中包含了应用程序的包名称,比如com.example.ExampleActivity
可以通过
setComponent()
setClass()
setClassName()
Intent
的构造方法来设置组件名称。

Action
以字符串的形式指定了需要执行的常见 Action(viewpick)。

在广播 Intent 时,本部分内容通告了要发生的 Action。 Action 很大程度上决定了 Intent 其余部分的内容 — 特别是数据和附件(extra)部分。

自定义供应用程序内部 Intent 使用(或者被其他应用程序用来启动本应用中的组件)的 Action 是可以的, 但通常应该使用 Intent 类或其他系统类定义的 Action 常量。 下面列举了常用的一些启动 Activity 的 Action:

ACTION_VIEW
如果需要用 Activity 显示一些信息,比如查看相册中的照片、地图应用中的地址信息等, 就可以在 startActivity() 的 Intent 中使用本 Action 。
ACTION_SEND
也就是所谓的“公用”Intent,如果用户需要与其他应用程序共享一些数据,比如 email 应用或社交分享应用, 就应该在 startActivity() 的 Intent 中使用本 Action。

要了解更多定义了常见 Action 的常量,请参阅 Intent 类的参考。 Android 系统的其他地方也定义了一些其他的 Action,比如 Settings 中就有打开系统设置应用中的某个屏幕的 Action。

Intent 的构造方法中,或者通过 setAction() 方法,也可以定义 Intent 的 Action。

如果定义了自己的 Action ,请一定要在名称中用应用程序的包名称作为前缀。 例如:

static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
数据
URI(一个Uri 对象) 指定了要操作的数据和(或)数据的 MIME 类型。 数据的类型通常取决于 Intent 的 Action。 例如,如果 Action 是 ACTION_EDIT ,则数据就应该包含需要编辑的文档的 URI 。

在创建 Intent 时,重点往往就是要定义数据的 URI 及其类型(MIME 类型)。 例如,能显示图片的 Activity 无法播放音频文件,即便 URI 格式类似也不行。 因此,指定数据的 MIME 类型可以帮助 Android 系统找到接收 Intent 的最佳组件。 不过, 有时候 MIME 类型也许可以从 URI 中推测出来 — 特别当数据 URI 为 content:,这表明数据位于本地设备且由某个 ContentProvider 控制,系统可以通过该 ContentProvider 知道数据的 MIME 类型。

如果只是设置数据的 URI ,请调用 setData()。 如果只是设置 MIME 类型,请调用 setType()。 必要的话,也可以用 setDataAndType() 同时设置这两个参数。

注意: 如果要同时设置 URI 和 MIME 类型,请勿调用 setData()setType(), 因为这两个方法会将另一个参数置空。 请一定要使用 setDataAndType() 来同时设置 URI 和 MIME 类型。

类型
一个包含了附加信息的字符串,内容有关处理 Intent 的组件类型。 虽然一个 Intent 中可以放入任意数量的类型描述符,但是大部分 Intent 都不需要指定本参数。 下面列举了一些常见的类型:
CATEGORY_BROWSABLE
目标 Activity 能够被 Web 浏览器启动,用于显示网页链接指向的数据 — 比如图片或者 e-mail 信息。
CATEGORY_LAUNCHER
Activity 是某个任务的起始 Activity,并显示在系统的应用程序启动器中。

要查看类型的完整列表,请参阅 Intent 类的说明文档。

addCategory() 方法可以指定一个类型。

上述参数(组件名称、Action、数据、类型)代表着 Intent 的特征定义。 通过读取这些参数,Android 系统就能够解析出所要启动的应用程序组件了。

当然,Intent 还可以附带一些无关于目标组件解析的信息。 Intent 中还可以提供:

附件
包含了附加信息的键值对,在执行所请求的 Action 时需要用到这些信息。 正如有些 Action 需要用到某类数据 URI 一样,有些 Action 还要用到附件信息。

添加附件数据的 putExtra() 方法有很多种,每个方法都有两个参数:键名和键值。 还可以创建一个包含所有的附件数据的 Bundle ,并用 putExtras() 把它插入到 Intent 中去。

例如,如果要用 ACTION_SEND 创建一个发送 email 的 Intent ,就可以用 EXTRA_EMAIL 键指定接收人,用 EXTRA_SUBJECT 键指定邮件主题。

对应标准的数据类型, Intent 类中定义了很多 EXTRA_* 常量。 如果需要定义自己的附件键名(用于应用程序接收 Intent ),请确保将应用程序的包名作为前缀。 例如:

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
标志位
Intent 类中定义的标志位,用作 Intent 的元数据。 这些标志位可以告知 Android 系统一些 Activity 的启动信息,包括 Activity 的启动方式(如该 Activity 所属的 任务), 和启动之后的处理方式(如该 Activity 是否在最近常用 Activity 列表中显示)。

更多信息,请参阅 setFlags() 方法。

显式 Intent 示例

显式 Intent 是用于启动指定组件的 Intent,比如应用程序内部的某个特定 Activity 或 服务。 要创建一个显式 Intent,请为 Intent 对象给定组件名称 — 其他的 Intent 参数都是可选的。

例如,假设应用程序中已有一个名为 DownloadService 的服务, 用于从 Web 上下载一个文件,你就可以用以下代码来启动它:

 // 在 Activity 中执行,因此 'this' 指的是上下文 Context
// fileUrl 是个 URL 字符串,如"http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

构造方法 Intent(Context, Class) 给出了 Context 和组件对象 Class。 因此,该 Intent 将显式启动应用程序中的 DownloadService 类。

关于创建和启动服务的详细信息,请参阅 服务 指南

隐式 Intent 示例

隐式 Intent 指定了一个 Action,当前设备上所有可执行这个 Action 的应用程序都可以被它激活。 如果当前应用程序没有能力执行这个 Action,而有其他应用程序可以处理且可以让用户使用它,隐式 Intent 就非常有用了。

例如,假设用户有些数据需要与其他人分享,就可以用 ACTION_SEND Action 创建一个 Intent,并将需分享的数据放入附件中。 只要用该 Intent 调用 startActivity() ,用户就可以启动某个应用程序并分享数据。

提醒: 有可能任何应用程序都无法处理发给 startActivity() 的隐式 Intent 。 如果是这样,调用将会失败,应用程序就会崩溃。 为了判断是否存在可接收 Intent 的 Activity ,请调用 Intent 对象的 resolveActivity() 方法。 如果结果为非空,则表示至少有一个应用程序可以处理该 Intent , startActivity() 的调用就是安全的。 如果结果为 null,就不要使用该 Intent。如果可能的话,请关闭那些提交该 Intent 的功能。

 // 通过字符串创建文字信息
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType(HTTP.PLAIN_TEXT_TYPE); // "text/plain" MIME type // 检查是否有可处理此 Intent 的 Activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}

注意: 这种情况下,没有使用 URI , 而是声明了 Intent 的数据类型,以指明附件中包含的内容。

当调用 startActivity() 时,系统会检查所有已安装的应用程序,进而确定可以处理这种 Intent 的应用(带有 ACTION_SEND 的 Intent 和包含“"text/plain”数据的 Intent)。 如果可处理该 Intent 的应用程序只有一个,则会立即打开该应用并传入该 Intent。 如果有多个 Activity 都可以接收该 Intent ,则系统会显示一个对话框,用户可以从中采用一个。

Android开发-API指南-Intent和Intent过滤器

图 2.选择对话框

强制打开应用程序选择对话框

如果有超过一个应用程序都可以响应某隐式 Intent,则用户可以选用其中一个并指定为该 Action 的默认处理程序。 假如从这时开始,用户都期望用同一个应用程序执行这类 Action ,比如打开网页(用户通常会优先选用一种浏览器), 那这种做法是非常合适的。

但是,如果总是有多个应用程序可以响应该 Intent,并且用户每次都需要使用不同的应用程序, 那就应该显示一个选择对话框。 该对话框每次都会要求用户选择一个用于处理 Action 的应用程序(用户无法为 Action 选择默认应用程序)。 例如,假设应用程序用 ACTION_SEND 执行“共享”操作,用户可能需要根据当前环境来选用一个应用程序, 所以一定要使用选择对话框,如图2所示。

要显示选择对话框,请用 createChooser() 创建一个 Intent 并将其传入 startActivity()。 例如:

 Intent intent = new Intent(Intent.ACTION_SEND);
... // 用户界面上的文字请保证使用字符串资源
// 这里可以显示一些信息,比如 "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// 创建显示选择界面的 Intent
Intent chooser = Intent.createChooser(intent, title); // 检查是否至少存在一个可处理该 Intent 的Activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}

上述对话框显示了一个应用程序列表,这些应用都可以响应传给 createChooser() 的 Intent ,对话框的标题也由其给定。

接收隐式 Intent


要将应用程序可接收的隐式 Intent 公布出去,请在 manifest 文件中用 <intent-filter> 元素为每个组件声明一个或多个 Intent 过滤器。 每个 Intent 过滤器定义了其可根据 Intent 的 action 、data 和 category 接受的 Intent 类型。 只有符合了组件中某个过滤器的条件,系统才会向组件分发该隐式 Intent 。

注意: 显式 Intent 一定是分发给目标组件的,无论组件中声明了什么 Intent 过滤器。

应用程序组件应该为每个可完成的任务声明独立的过滤器。 例如,图册应用中的某个 Activity 可能会包含两个过滤器: 一个用于查看图片,另一个用于编辑图片。 在启动时, Activity 会检查 Intent 并根据其中的信息决定如何操作(比如是否显示编辑控件)。

每个 Intent 过滤器都通过 Manifest 文件中的一项 <intent-filter> 元素来定义,该元素包含在相应的应用程序组件中(比如 <activity> 元素)。在 <intent-filter> 中,可以使用一个或多个以下三种元素来指定能够接受的 Intent 类型:

<action>
name 属性中声明可接受的 Intent 的 Action。 属性值必须是表示 Action 的纯字符串,而不能是在类中定义的常量。
<data>
通过一个或多个属性来声明可接受的数据类型,每个属性对应着数据 URI 的各个部分( schemehostportpath 等等)。
<category>
name 属性中声明可接受的 Intent 类型。 属性值必须是表示 Category 的纯字符串,而不能是在类中定义的常量。

注意: 为了能够接收到隐式 Intent ,Intent 过滤器中必须包含 CATEGORY_DEFAULT 的类型。 startActivity()startActivityForResult() 方法认为所有的 Intent 都应该声明了 CATEGORY_DEFAULT 类型。 如果 Activity 的 Intent 过滤器中未能给出这个类型,则不会有隐式 Intent 分发给它。

例如,下面是一个声明了 Intent 过滤器的 Activity,用于接收文本型数据的 ACTION_SEND Intent。

 <activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>

可以创建包含了多个 <action> <data> <category> 的过滤器。 如果是这样,请确认该组件能够处理这些过滤条件的各种组合即可。

如果需要处理多种类型的 Intent ,但仅限于某些特定 Action、Data 和 Category 的组合,那就需要创建多个 Intent 过滤器。

限制对组件的访问

使用 Intent 过滤器是一种不太安全的方式,无法阻止其他应用程序启动你的组件。 虽然 Intent 过滤器限制组件只能响应某些指定类型的隐式 Intent , 但只要其他应用程序的开发人员知道了组件名称,还是有可能通过显式 Intent 来启动该组件。 如果一定只有应用程序自身才能启动自己的组件,请将该组件的 exported 属性设为“false”。

通过与过滤器的三个元素进行对比,隐式 Intent 将接受系统的检测。 Intent 要能分发到组件,必须三个条件全部通过。 只要有一个条件不满足, Android 系统就不会把该 Intent 分发给组件。 不过,组件可能拥有多个 Intent 过滤器,所以一个没通过还有可能通过另一个。 关于系统对 Intent 的分发方式,更多信息请参阅后续章节 Intent 解析

提醒: 为了避免无意间运行了其他应用程序的 Service ,请一定要使用显式 Intent 来启动自己的服务,并且不要为服务声明 Intent 过滤器。

注意: 所有的 Activity 都必须在 Manifest 文件中声明 Intent 过滤器。 但广播接收器的 Intent 过滤器可以实现动态注册,这通过调用 registerReceiver() 来完成。 然后可以通过 unregisterReceiver() 来注销。 通过这种方式,应用程序可以仅在运行过程中的某个阶段对指定的广播消息实现侦听。

过滤器示例

为了更好地理解 Intent 过滤器的运行方式,请参阅下面的 Manifest 文件片段,它来自于某个社交类应用。

 <activity android:name="MainActivity">
<!-- This activity is the main entry, should appear in app launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <activity android:name="ShareActivity">
<!-- This activity handles "SEND" actions with text data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google.panorama360+jpg"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
</intent-filter>
</activity>

第一个 Activity — MainActivity — 是程序的主入口, 当用户第一次通过启动器中的图标启动应用程序时,将会打开该 Activity :

  • ACTION_MAIN 指明了这是主入口,且不用包含任何 Intent 数据。
  • CATEGORY_LAUNCHER 指明了该 Activity 的图标应该在系统的应用程序启动器中显示出来。如果 <activity> 元素未用 icon 给出图标的定义,系统会使用 <application> 中定义的图标。

为了要让 Activity 能够在应用程序启动器中显式出来,上述两项必须放在一起成对给出。

第二个 Activity — ShareActivity — 用于实现文本和多媒体数据的共享。 用户可以从 MainActivity 中跳转到 ShareActivity ,也可以从其他应用程序中直接进入, 只要发起一个匹配两个过滤器之一的隐式 Intent 即可。

注意: MIME 类型 application/vnd.google.panorama360+jpg 是一种特殊的数据类型,定义了可用 Google panorama API 进行处理的全景照片,

使用 Pending Intent


PendingIntent 对象是对 Intent 对象的二次封装。 PendingIntent 的主要用途是对需要使用其 Intent 的外部应用程序进行授权,使得它就像在本应用程序的进程中运行一样。

Pending Intent 的主要应用场景包括:

  • 当用户通过 通知 进行某项操作时,需要执行的 Intent ( Android 系统的 NotificationManager 将会执行此 Intent)。
  • 当用户通过 App Widget 进行某项操作时,需要执行的 Intent (主屏幕管理应用程序将会执行此 Intent)。
  • 未来某个时间点需要执行的 Intent( Android 系统的 AlarmManager 将会执行此 Intent)。

因为每种 Intent 对象都被设计为仅能由某个指定类型的组件进行处理( ActivityServiceBroadcastReceiver 之一), 所以 PendingIntent 也必须如此。 在使用 Pending Intent 时,应用程序无法通过 startActivity() 之类的调用来执行 Intent 。 而是必须在创建 PendingIntent 时,调用以下创建方法来表明对应的组件类型:

上述创建 PendingIntent 的方法就已经是需要用到的全部 PendingIntent 方法,除非需要从其他应用程序接收 Pending Intent 。

每个方法都会带入当前应用程序的 Context、 要封装的 Intent 以及一个或多个指明 Intent 使用方式的标志位(比如 Intent 是否可以多次使用)。

关于使用 Pending Intent 的更多信息,在各个使用场景的文档中都有给出,比如 通知App Widgets API 指南中。

Intent 解析


当系统收到一个启动 Activity 的隐式 Intent 后,将会查找最合适的 Activity , 这通过比较 Intent 和 Intent 过滤器的三个部分来实现:

  • Intent 的 Action
  • Intent 的数据(包括 URI 和 数据类型)
  • Intent 的类型

以下章节说明了 Intent 与组件的匹配方式,基于应用程序的 Manifest 文件中声明的 Intent 过滤器。

Action 验证

为了指定可接受的 Intent Action,Intent 过滤器可以声明0个以上的 <action> 元素。例如:

<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
...
</intent-filter>

为了通过这个过滤器的验证, Intent 中指定的 Action 必须匹配上述过滤器中的一种 Action。

如果过滤器没有给出任何 Action , Intent 就没有可匹配的目标,因此所有的验证都会失败。 但是,如果是 Intent 未给出 Action ,则它会通过验证(假设过滤器中至少包含了一个 Action)。

Category 验证

为了指定可接收的 Intent 类型, Intent 过滤器可以声明0个以上的 <category> 元素。例如:

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

为了通过类型验证, Intent 中的每个 Category 都必须与过滤器中的相匹配。 反之则不然 — Intent 过滤器中声明的 Category 可以多于 Intent 中的,验证将会通过。 因此,不带任何 Category 的 Intent 也将会通过验证,不管过滤器中的 Category 怎么声明都会通过。

注意: Android 会对传入 startActivity()startActivityForResult() 的隐式 Intent 自动应用 CATEGORY_DEFAULT 类型。 因此,如果 Activity 需要接收隐式 Intent ,它就必须在 Intent 过滤器中包含 "android.intent.category.DEFAULT" (正如上述 <intent-filter> 所示)。

Data 验证

为了指定可接收的 Intent 数据, Intent 过滤器可以声明0个以上的 <data> 元素。例如:

 <intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
...
</intent-filter>

每个 <data> 元素都可以指定一个 URI 和一个数据类型(MIME 媒体类型)。 URI 的每个部分都对应有单独的属性 — schemehostportpath

<scheme>://<host>:<port>/<path>

例如:

content://com.example.project:200/folder/subfolder/etc 

在上述 URI 中, Scheme 是 content , Host 是 com.example.project , Port 是 200 , Path 是 folder/subfolder/etc

这些属性都是 <data> 元素的可选项,但却有顺序的依赖关系:

  • 如果未给出 Scheme ,则 Host 将被忽略。
  • 如果未给出 Host ,则 Port 将被忽略。
  • 如果 Scheme 和 Host 均未给出,则 Path 将被忽略。

在把 Intent 中的 URI 和过滤器中的 URI 规则进行比较时,只会按照过滤器 URI 的各个部分来进行。 例如:

  • 如果过滤器只声明了 Scheme ,则所有带有此 Scheme 的 URI 都将是与其匹配的。
  • 如果过滤器声明了 Scheme 和 Authority ,但没有声明 Path , 则所有带有同样 Scheme 和 Authority 的 URI 都会通过该过滤器, Path 怎么样都无所谓。
  • 如果过滤器同时声明了 Scheme 、 Authority 和 Path , 则只有那些 Scheme 、 Authority 和 Path 都符合的 URI 才能通过该过滤器。

注意: Path 规则中可以包含通配符(*),这样只需要匹配部分路径名称即可。

数据验证将会同时比较 Intent 和过滤器的 URI 和 MIME 类型。 规则如下:

  1. 如果 Intent 即不包含 URI ,也不含 MIME 类型, 则仅当过滤器也未指定任何 URI 和 MIME 类型时,才能通过验证。
  2. 如果 Intent 包含了 URI ,但不含 MIME 类型(既没有显式给出也无法从 URI 中推导出来), 则仅当 URI 与过滤器的 URI 规则吻合且过滤器未指定 MIME 类型时,才能通过验证。
  3. 如果 Intent 包含了 MIME 类型,但不含 URI , 则仅当过滤器中列出了相同的 MIME 类型且未指定 URI 规则时,才能通过验证。
  4. 如果 Intent 同时包含了 URI 和 MIME 类型(显式给出或可从 URI 中推导出来), 则当过滤器中列出了相同的 MIME 类型时通过 MIME 类型验证。 当 URI 与过滤器中的 URI 相匹配,或者 URI 带有 content:file:且过滤器未指定 URI 时,通过 URI 验证。 也就是说,如果某个组件的 Intent 过滤器给出了 MIME 类型, 那么就表示它将支持 content:file: 数据的处理。

最后一条规则说明,系统期望所有组件都能够读取文件或者 Content Provider 中的本地数据。 因此,过滤器只需要列出数据类型即可,不必显式地命名 content:file: 类型的 Scheme。 这是一种典型的应用场景。 例如,下述的 <data> 元素将会通知 Android 系统,该组件可以从 Content Provider 读取图片数据并显示出来:

<intent-filter>
<data android:mimeType="image/*" />
...
</intent-filter>

因为大部分数据都是由 Content Provider 发布出来的, 所以指定数据类型但不给出 URI 也许是 Intent 过滤器最常见的配置方式。

Intent 过滤器另一种常见的配置方式就是包含 Scheme 和数据类型。 例如,类似下述的 <data> 元素将会通知 Andorid 系统,为了执行 Action ,该组件可以从网络读取视频数据:

<intent-filter>
<data android:scheme="http" android:type="video/*" />
...
</intent-filter>

Intent 匹配

Intent 与 过滤器的匹配机制,不仅用于查找需要激活的组件,还用于发现当前设备中所有组件的某些信息。 例如,通过把所有带有 ACTION_MAIN Action 和 CATEGORY_LAUNCHER Category 过滤器的 Activity 找出来,管理主屏幕的应用程序就可以组建应用程序启动器。

应用程序可以采用统一的方式来使用 Intent 过滤机制。 PackageManager 拥有一些 query...() 方法, 这些方法将会返回能够接受某类 Intent 的全部组件, 类似的另一些 resolve...() 方法将会确定响应某个 Intent 的最佳组件。例如, queryIntentActivities() 将返回可执行传入参数 Intent 的 Activity 列表, queryIntentServices() 将返回类似的服务列表。 这两个方法均不会激活组件,而只是列出能够响应 Intent 的组件。 另一个类似的方法,就是列出广播接收器列表的 queryBroadcastReceivers()