我们在前面的 Activity、Service 和 BroadcastReceiver 中重复的用到 Intent,我们用它来启动 Activity、启动 Service、传递广播。它作为一个消息传递的对象,活跃在各个组件之间。
Intent 可以分为两种类型:
显示 Intent:直接(使用类名)指定要启动的组件。例如跳转到一个 Activity、启动一个新的服务,系统将立即启动 Intent 对象中指定的应用组件。构建显示 Intent 只需要指定组件名称
,其余属性均为可选。
隐式 Intent:不会直接指定特定的组件,而是声明要执行的动作。Android 系统通过将 Intent 的内容与在设备上的其他应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的组件,如果找到了,则启动该组件并向其传递 Intent 对象,如果有多个过滤器可以响应,则由用户来选择启动哪一个。
Intent 对象携带了 Android 系统用来确定要启动哪个组件的信息(例如,准确的组件名称或应当接收该 Intent 的组件类别),以及收件人组件为了正确执行操作而使用的信息(例如,要采取的操作以及要处理的数据)。
一个 Intent 包含如下主要信息:
组件名称(ComponentName):表示要启动的组件,该选项是可选的,但是显示 Intent 一定要有,如果没有组件名称,则该 Intent 就是隐式 Intent。
我们可以使用 setComponent()
、setClass()
、setClassName()
或者 Intent 的构造函数来设置组件名称。
操作(Action):使用一个字符串来指定要执行的通用操作,供 Intent 在您的应用中使用。
我们可以使用 setAction()
或 Intent 的构造函数来指定操作。
以下是一些用于启动 Activity 的常见操作:
ACTION_VIEW:如果你拥有一些某项 Activity 可向用户展示的信息(例如,要使用图库应用查看的照片;或者要使用地图应用查看的地址),请吃使用此操作与 startActivity() 结合使用。
ACTION_SEND:这也成为“共享” Intent。如果您拥有的一些用户可通过其他应用(例如,电子邮件应用或社交共享应用)共享的数据,则应使用 Intent 将此操作与 startActivity() 结合使用。
数据(Data):引用待操作数据和/或该数据 MIME 类型的 URI。提供的数据类型通常由 Intent 的操作决定。
创建 Intent 时,除了指定 URI 以外,指定数据类型往往也很重要,例如,能够显示图像的 Activity 可能无法播放音频文件,即便 URI 格式十分类似时也是如此。因此,指定数据的 MIME 类型有助于 Android 系统找到接收 Intent 的最佳组件。
我们可以通过 setData() 来设置数据;通过调用 setType() 来设置 MIME 类型;也可以通过 setDataAndType() 同时显式设置两者。
类别(Category):一个包含应处理 Intent 组件类型的附加信息的字符串。你可以将任意数量的类别描述放入到一个 Intent 中,但大多数 Intent 均不需要类别。
我们可以使用 addCategory() 指定类别。
以下是一些常见类别:
CATEGORY_BROWSABLE:目标 Activity 允许本身通过网络浏览器启动,以显示链接引用的数据,如图像或电子邮件。
CATEGORY_LAUNCHER:该 Activity 是任务的初识 Activity,在系统的应用启动器中列出。
额外数据(Extra):用来携带完成请求操作所需的附加信息的键值对。
我们使用 putExtra() 方法添加 Extra 数据,还可以创建一个包含所有 extra 数据的 Bundle 对象,然后使用 putExtras() 将 Bundle 插入到 Intent 中。
标志(Flag):在 Intent 类中定义的、充当 Intent 元数据的标志。标志可以指示 Android 系统如何启动 Activity,以及启动后如何处理。
可以使用 setFlags() 方法设置标志。
显示 Intent 就不用说了,指定哪个组件接收,就是哪个组件接收,实锤没啥好说的。
但是对于隐式 Intent 来说,要决定该组件可以接收哪些隐式 Intent,需要在清单文件中使用 <intent-filter>
元素为每个应用组件声明一个或者多个过滤器。然后该过滤器根据 Intent 的 操作(action)、数据(data)、类别(category)来确定自身是否可以响应该隐式 Intent,当隐式 Intent 可以通过某个过滤器时,系统才会将该 Intent 传递给该组件。当有多个组件可以响应的时候,则弹出提示框由用户选择使用哪个组件响应。
在 <intent-filter>
内部,可以使用三个元素中的一个或者多个来指定该组件可以响应哪些 Intent:
<action>
:表示可以接收的 Intent 的操作(action),该值必须是文本字符串值。
<data>
:表示可以接收的 Intent 数据类型(data),可以由一个或者多个指定数据 URI 和 MIME 类型表示。
<category>
:声明可以接收的 Intent 类别(category),该值必须是文本字符串。
为了接收隐式 Intent,必须将
android.intent.category.DEFAULT
类别包括在<intent-filter>
中,如果没有在过滤器中声明此类别,则隐式 Intent 不会解析为您的 Activity。
有以下几个点需要注意:
一个组件可以声明多个过滤器。
一个过滤器可以包含多个 action
、data
和 category
创建过滤器时,仅需确定组件能够处理这些过滤器元素的任何及所有组合即可。
系统会将 Intent 与过滤器中的元素进行比较,只有完全通过,才会将 Intent 传递给该组件。
由于一个组件可以有多个过滤器,一个过滤器没有通过,Intent 可能会通过另一个过滤器。
Activity 必须在清单中声明 Intent 过滤器,广播接收器可以在 Java 文件中调用 registerReceiver()
方法动态注册,调用 unregisterReceiver()
注销。
对于服务(Service)来说,请使用显示 Intent。
当系统接收到隐式 Intent 以启动 Activity 时,它根据以下三个方面将该 Intent 与 <intent-filter>
进行比较,以搜索该 Intent 的最佳响应 Activity:
Intent 操作(action)
Intent 数据(URI 和 MIME 类型)
Intent 类别
操作匹配
前面说过,一个 intent-filter 可以不声明 <acion>
元素,也可以有多个 <acion>
元素。
如果要使 Intent 通过该过滤器,则 Intent 中指定的 action(通过 setAction() 设置) 必须与过滤器中列出的某一个 action 元素匹配。如若不匹配,则不会通过该过滤器。
数据匹配
intent-filter 可以不声明 data 元素,也可以声明多个 data 元素。
每个 data 元素都可以指定 URI 结构和 MIME 类型。
URI 的每个部分均包含单独的 scheme、host、port 和 path 属性。
例如在 content://com.example.project:200/folder/subfolder/etc
中:
scheme 是 content
host 是 com.example.project
port 是 200
path 是 folder/subfolder/etc
在 intent-filter 的 data 元素中,上述的每个属性均为可选,但存在线性依赖关系:
如果未指定 scheme,则会忽略 host
如果未指定 host,则会忽略 port
如果未指定 scheme 和 host,则会忽略 path
将 Intent 中的 URI 和过滤器中的 URI 规范进行比较时,它仅与过滤器中包含的部分 URI 进行比较。例如:
如果 intent-filter 仅指定 scheme,则具有该 scheme 的所有 URI 均与该过滤器匹配
如果 intent-filter 指定 scheme 和 host,但没有指定 path,则具有相同 scheme 和 host 的所有 URI 都会通过过滤器。
如果 intent-filter 指定 scheme、host 和 path,那么仅具有相同 scheme、host 和 path 的 URI 才会通过过滤器。
path 可以使用通配符
*
来替代,因此仅需部分匹配 path 即可。
对于 Intent 中的 URI 和 MIME 类型与 intent-filter 中的 URI 和 MIME 类型比较规则如下:
仅当 intent-filter 没有指定任何 URI 或 MIME 类型时,不包含 URI 和 MIME 类型的 Intent 才能通过。
intent-filter 没有指定 MIME 类型只指定了 URI 的时候,只有同样包含了可以匹配的 URI 并且同样没有指定 MIME(没有显式指定,也无法通过 URI 推断) 的 Intent 可以通过。
仅当 intent-filter 列出相同的 MIME 类型 且没有指定 URI 时候,匹配 MIME 类型但不包含 URI 的 Intent 才会通过过滤器。
仅当 MIME 类型与过滤器中列出的类型匹配时,同时包含 URI 类型和 MIME 类型(通过显式声明,或可以通过 URI 推断得出)的 Intent 才会通过测试的 MIME 类型部分。 如果 Intent 的 URI 与过滤器中的 URI 匹配,或者如果 Intent 具有 content: 或 file: URI 且过滤器未指定 URI,则 Intent 会通过测试的 URI 部分。 换言之,如果过滤器只是列出 MIME 类型,则假定组件支持 content: 和 file: 数据。
类别匹配
intent-filter 可以不声明任何 category 元素,也可以声明多个。
Intent 要想通过 intent-filter,那么 Intent 中的每个 catetory(通过 addCategory() 添加)都必须和 intent-filter 中的 category 元素匹配。
相反,intent-filter 中可以包含多个 category,但只有部分 category 元素可以响应某个 Intent,那么该 Intent 同样可以通过该 intent-filter。
如需 Activity 接收隐式 Intent,则必须将 "android.intent.category.DEFAULT" 的类别包括在其 Intent 过滤器中。
PendingIntent 是 Intent 的包装器。PengingIntent 的主要目的是授权外部 App 使用本 App 中包含的 Intent,就像是它从你的 App 本身进行中执行的一样。
PendingIntent 的主要用例包括:
声明用户使用您的通知执行操作时所要执行的 Intent(Android 系统的 NotificationManager 执行 Intent)。
声明用户使用您的 应用小部件执行操作时要执行的 Intent(主屏幕应用执行 Intent)。
声明未来某一特定时间要执行的 Intent(Android 系统的 AlarmManager 执行 Intent)。
由于每个 Intent 对象均设计为由特定类型的应用组件(Activity、Service 或 BroadcastReceiver)进行处理,因此还必须基于相同的考虑因素创建 PendingIntent。使用待定 Intent 时,应用不会使用调用(如 startActivity())执行该 Intent。相反,通过调用相应的创建器方法创建 PendingIntent 时,您必须声明所需的组件类型:
PendingIntent.getActivity(),适用于启动 Activity 的 Intent。
PendingIntent.getService(),适用于启动 Service 的 Intent。
PendingIntent.getBroadcast(),适用于启动
BroadcastReceiver 的 Intent。
除非您的应用正在从其他应用中接收待定 Intent,否则上述用于创建 PendingIntent 的方法可能是您所需的唯一 PendingIntent 方法。
每种方法均会提取当前的应用 Context、您要包装的 Intent 以及一个或多个指定应如何使用该 Intent 的标志(例如,是否可以多次使用该 Intent)。
一个 Notification 的例子:
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
mBuilder.setSmallIcon(R.drawable.notification_icon)
mBuilder.setContentTitle("My notification")
mBuilder.setContentText("Hello World!");
Intent resultIntent = new Intent(this, ResultActivity.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this,0,resultIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
int mNotificationId = 001;
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Builds the notification and issues it.
mNotifyMgr.notify(mNotificationId, mBuilder.build());
请参考: 通用 Intent
官方文档
《第一行代码》《疯狂 Android 讲义》