Intent和IntentFilter的笔记(develper.android.com)

本文深入讲解 Android 中 Intent 的概念及其用途,包括启动 Activity、Service 和 BroadcastReceiver 的方法,以及显式和隐式 Intent 的区别。同时介绍了 Intent 的组成部分,如操作、数据、类别等,并提供了示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

Intent翻译为意图,是android中Activity,Service,BroadcastReciver三大组件之间的信使,负责开启它们并可以传递信息,即消息传递对象,传递的信息可以是基本数据类型,也可以是一个对象。

  1. 启动Activity:startActivity();startActivityForResult(); onActivityResult();
  2. 启动Service:startService();或bindService();
  3. 启动BroadcastReceiver:sendBroadcast();sendOrderedBroadcast();sendStickyBroadcast();

类型

  1. 显式Intent:显式地指定要启动的组件名称,通常用于启动自己的应用中的组件,如启动service在后台下载文件
  2. 隐式Intent:不声明要启动的组件名称,而是通过传入一段代表某种操作的字符串,从而允许能执行该种操作的组件启动并接受它,通常是其他应用中的组件
    Inten的隐式启动方式

[^footnote]从api21开始,如果使用隐式Intent调用bindService,系统会抛出异常

注意

为了避免无意中运行不同应用的 Service,请始终使用显式 Intent 启动您自己的服务,且不必为该服务声明 Intent 过滤器。

过滤器示例

构造Intent

Intent携带了android系统用来确定要启动哪个组件的信息

组件名

这是可选的,如果有,则Intent必定是显式的,没有则是隐式的,如果是开启service,为了确保应用的安全性,务必使用显式(隐式有可能开启其他应用的service)

操作 action

一个声明常规操作的字符串,系统定义了一些常用操作,也可以自定义

数据 data

引用待操作数据和/或数据mime类型的Uri(URI对象)提供的数据类型通常由该Intent的操作决定
这里写图片描述
有时候,隐式创建Intent的时候,仅仅凭借操作和数据不能准确地启动正确的组件,比如播放音频结果却启动了显示图像的activity,因为URI格式可能十分相似。所以,指定数据的MIME类型也很重要(不过有时候,MIME类型可以从URI中看出)
要仅设置数据 URI,请调用 setData()。要仅设置 MIME 类型,请调用 setType()。如有必要,您可以使用 setDataAndType() 同时显式设置二者。

类别 category

一个包含应处理 Intent 组件类型的附加信息的字符串。您可以将任意数量的类别(可能有多个或者一个都没有)描述放入一个 Intent 中,但大多数 Intent 均不需要类别
- CATEGORY_BROWSABLE
目标 Activity 允许本身通过 Web 浏览器启动,以显示链接引用的数据,如图像或电子邮件。
- CATEGORY_LAUNCHER
该 Activity 是任务的初始 Activity,在系统的应用启动器中列出
通过intent.addCategory() 向Intent中指定类别

以上列出的这些属性(组件名称、操作、数据和类别)表示 Intent 的既定特征。通过读取这些属性,Android 系统能够解析应当启动哪个应用组件。

除了携带既定特征的信息,Intent还可以携带不影响其解析的信息:Extra Flags

Exra 额外数据

携带完成请求的附加信息的健值对,或者Bundle对象,然后使用putExtra()或者putExtras()放入intent中
例如,使用 ACTION_SEND 创建用于发送电子邮件的 Intent 时,可以使用 EXTRA_EMAIL 键指定“目标”收件人,并使用 EXTRA_SUBJECT 键指定“主题”,之后一旦有intent想要访问该组件,则必须携带除动作外的extra,并将健设置为EXTRA_EMAIL
注*Intent 类将为标准化的数据类型指定多个 EXTRA_ 常量。如需声明自己的附加数据 键(对于应用接收的 Intent ),请确保将应用的软件包名称作为前缀。例如:

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Flags 标志

标示Intent该如何启动activity,Receiver,以及启动后如何处理,其值在Intent类中定义,充当Intent的元数据
这里写图片描述

示例

显式Intent示例

Intent downloadIntent = new Intent(this, DownloadService.class);
// fileUrl是网络中的一个url地址,通过parse方法转化成URI
//比如"http://www.example.com/image.png"
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

隐式Intent示例

//创建一个string类型的文本
Intent sendIntent = new Intent();
//设置操作/动作 action
sendIntent.setAction(Intent.ACTION_SEND);
//设置额外数据 extra,指定其类型为Intent.EXTRA_TEXT
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
//设置类型 type
sendIntent.setType("text/plain");

// 用户可能没有任何应用处理你发送到 startActivity() 的隐式 Intent。如果出现这种情况,则调用将会失败,且应用会崩溃。使用如下方式判断是否有组件接受你的intent
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}
//上面构造的intent,没有设置data,而是通过声明了Intent的数据类型,指定了Extra所携带的内容类型

强制应用选择器

说明:当有多个组件响应隐式intent的时候,系统会淡出一个选择列表框让用户选择一个,默认情况下,列表框可以让用户选择该intent的默认启动组件,下次再次启动时,就不会弹出对话框了。如果要让用户无法为该操作选择默认启动组件的话,则可以使用强制应用选择器。
使用方法: 使用createChooser()包装Intent
示例

Intent sendIntent = new Intent(Intent.ACTION_SEND);

//选择器的标题,就像“选择如下的应用分享您的图片”
String title = getResources().getString(R.string.chooser_title);
Intent chooser = Intent.createChooser(sendIntent, title);
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

接受隐式Intent

对于接受方来说,要公布本组件可以接受哪些隐式intent,应在清单文件中为该组件设置意图过滤器(intent filter)可以设置多个,它根据Intent的操作(action),数据(data),类别(category)指定自己所接受的intent类型,仅当隐式intent至少满足一个过滤器时,才能让接受者接受。
注意:显式 Intent 始终会传递给其目标,无视目标的意图过滤器
应用组件应当为每个单独的功能/作业设置各自的过滤器,比如一个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>

限制对组件的访问
使用 Intent 过滤器时,无法安全地防止其他应用启动组件。尽管 Intent 过滤器将组件限制为仅响应特定类型的隐式 Intent,但如果开发者确定您的组件名称,则其他应用有可能通过使用显式 Intent 启动您的应用组件。如果必须确保只有您自己的应用才能启动您的某一组件,请针对该组件将 exported 属性设置为 “false”

IntentFilter 示例:
<activity android:name="MainActivity">
    <!-- 第一个 Activity MainActivity 是应用的主要入口点。当用户最初使用启动器图标启动应用时,该 Activity 将打开:
ACTION_MAIN 操作指示这是主要入口点,且不要求输入任何 Intent 数据。CATEGORY_LAUNCHER 类别指示此 Activity 的图标应放入系统的应用启动器。如果 <activity> 元素未使用 icon 指定图标,则系统将使用 <application> 元素中的图标。 -->
<!--这两个元素必须配对使用,Activity 才会显示在应用启动器中。-->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="ShareActivity">
    <!--  第二个 Activity ShareActivity 旨在便于共享文本和媒体内容。尽管用户可以通过从 MainActivity 导航进入此 Activity,但也可以从发出隐式 Intent(与两个 Intent 过滤器之一匹配)的另一应用中直接进入 ShareActivity。-->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- 多类型的共享文本和媒体内容的过滤器 -->
    <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>

使用PendingIntent,待定Intent


Intent解析

系统通过将 Intent 与所有这三个元素进行比较,根据过滤器测试隐式 Intent,suo隐式 Intent 若要传递给组件,必须通过所有这三项测试。如果 Intent 甚至无法匹配其中任何一项测试,则 Android 系统不会将其传递给组件。

  • Intent操作
  • Intent数据(URI和数据类型)
  • Intent类别

操作测试

<!--既可以写多个,也可以一个不写-->
<intent-filter>
    <action android:name="android.intent.action.EDIT" />
    <action android:name="android.intent.action.VIEW" />
    ...
</intent-filter>

类别测试

<!--既可以写多个,也可以一个不写-->
<intent-filter>
     <!--但是,如果这是activity的过滤器,要想让其他组件通过startActivity或者startActivityForReustl启动,则必须设置它为category.DEFAULT,因为Android 会自动将 CATEGORY_DEFAULT 类别应用于传递给 startActivity() 和 startActivityForResult() 的所有隐式 Intent-->
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    ...
</intent-filter>

数据测试

<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" ... />
    <data android:mimeType="audio/mpeg" android:scheme="http" ... />
    ...
</intent-filter
每个 <data> 元素均可指定 URI 结构和数据类型(MIME 介质类型)。URI 的每个部分均包含单独的 scheme、host、port 和 path 属性:
<scheme>//:<host>:<port>/<path>
例如:content://com.example.project:200/folder/subfolder/etc

在此 URI 中,架构是 content,主机是 com.example.project,端口是 200,路径是 folder/subfolder/etc
在 “data”元素中,上述每个属性均为可选,但存在线性依赖关系:

  • 如果未指定架构,则会忽略主机。
  • 如果未指定主机,则会忽略端口。
  • 如果未指定架构和主机,则会忽略路径。

将 Intent 中的 URI 与过滤器中的 URI 规范进行比较时,它仅与过滤器中包含的部分 URI 进行比较。例如:

如果过滤器仅指定架构,则具有该架构的所有 URI 均与该过滤器匹配。
如果过滤器指定架构和权限、但未指定路径,则具有相同架构和权限的所有 URI 都会通过过滤器,无论其路径如何均是如此。
如果过滤器指定架构、权限和路径,则仅具有相同架构、权限和路径 的 URI 才会通过过滤器。

注意:路径规范可以包含星号通配符 (),因此仅需部分匹配路径名即可。*

数据测试会将 Intent 中的 URI 和 MIME 类型与过滤器中指定的 URI 和 MIME 类型进行比较。规则如下:

A:仅当过滤器未指定任何 URI 或 MIME 类型时,不含 URI 和 MIME 类型的 Intent 才会通过测试。
B:对于包含 URI、但不含 MIME 类型(既未显式声明,也无法通过 URI 推断得出)的 Intent,仅当其 URI 与过滤器的 URI 格式匹配、且过滤器同样未指定 MIME 类型时,才会通过测试。
C:仅当过滤器列出相同的 MIME 类型且未指定 URI 格式时,包含 MIME 类型、但不含 URI 的 Intent 才会通过测试。
D:仅当 MIME 类型与过滤器中列出的类型匹配时,包含 URI 和 MIME 类型(通过显式声明,或可以通过 URI 推断得出)的 Intent 才会通过测试的 MIME 类型部分。如果 Intent 的 URI 与过滤器中的 URI 匹配,或者如果 Intent 具有 content: 或 file: URI 且过滤器未指定 URI,则 Intent 会通过测试的 URI 部分。换而言之,如果过滤器仅列出 MIME 类型,则假定组件支持 content: 和 file: 数据。
最后一条规则,即规则 (d),反映了期望组件能够从文件中或内容提供商处获得本地数据。因此,其过滤器可以仅列出数据类型,而不必显式命名 content: 和 file: 架构。这是一个典型的案例。例如,下文中的 <data> 元素向 Android 指出,组件可从内容提供商处获得并显示图像数据:
<intent-filter>
    <data android:mimeType="image/*" />
    ...
</intent-filter>

由于大部分可用数据均由内容提供商分发,因此指定数据类型(而非 URI)的过滤器也许最为常见。

另一常见的配置是具有架构和数据类型的过滤器。例如,下文中的 元素向 Android 指出,组件可从网络中检索视频数据以执行操作:

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

Intent匹配

主页应用通过使用指定 ACTION_MAIN 操作和 CATEGORY_LAUNCHER 类别的 Intent 过滤器查找所有 Activity,以此填充应用启动器。
PackageManager 提供了一整套 query…() 方法来返回所有能够接受特定 Intent 的组件。此外,它还提供了一系列类似的 resolve…() 方法来确定响应 Intent 的最佳组件。例如,queryIntentActivities() 将返回能够执行那些作为参数传递的 Intent 的所有 Activity 列表,而 queryIntentServices() 则可返回类似的服务列表。这两种方法均不会激活组件,而只是列出能够响应的组件。对于广播接收器,有一种类似的方法: queryBroadcastReceivers()。

注:整理自谷歌开发者文档
Intent的谷歌官方api链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值