【Android】你可能需要了解Intent的那些事

如果你觉得自己,整天累得跟狗一样。你真是误会大了,狗根本没有你这么累。人生就跟在跑步机上似的,你已经累吐血了,可是在别人眼里,你还在原地踏步。

Intent

Intent 是一个消息传递对象,你可以使用它从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件之间的通信,但其基本用例主要包括以下三个:

  • 启动Activity: startActivity()
  • 启动服务: bindService()
  • 传递广播: sendBroadcast()

Intent类型

Intent 分为两种类型:

  • 显式 Intent:按名称(完全限定类名)指定要启动的组件。
  • 隐式 Intent:不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。

创建 显式 Intent 启动 Activity 或服务时,系统将立即启动 Intent 对象中指定的应用组件。

创建 隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。Intent如果 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并将其传递给对象。如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。


隐式 Intent 如何通过系统传递以启动其他 Activity 的图解

为了确保应用的安全性,启动 Service 时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。从
Android 5.0(API 级别 21)开始,如果使用隐式 Intent 调用 bindService(),系统会抛出异常。

构建 Intent

  • 组件名称(ComponentName):这是可选项,但也是构建显式 Intent 的一项重要信息,这意味着 Intent 应当仅传递给由组件名称定义的应用组件。Intent 的这一字段是 ComponentName 对象,您可以使用目标组件的完全限定类名指定此对象,其中包括应用的软件包名称。
  • 操作(Action):指定要执行的通用操作(例如,“查看”或“选取”)的字符串。
  • 数据(Data):引用待操作数据和/或该数据 MIME 类型的 URI(Uri 对象)。提供的数据类型通常由 Intent 的操作决定。

要仅设置数据 URI,请调用 setData()。要仅设置 MIME 类型,请调用 setType()。如有必要,您可以使
用 setDataAndType() 同时显式设置二者。
警告:若要同时设置 URI 和 MIME 类型,请勿调用 setData() 和 setType(),因为它们会互相抵消彼此
的值。请始终使用 setDataAndType() 同时设置 URI 和 MIME 类型。

  • 类别(Category):一个包含应处理 Intent 组件类型的附加信息的字符串。您可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。
  • Extra:携带完成请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据 URI 一样,有些操作也使用特定的附加数据。例如,使用 ACTION_SEND 创建用于发送电子邮件的 Intent 时,可以使用 EXTRA_EMAIL键指定“目标”收件人,并使用 EXTRA_SUBJECT 键指定“主题”。
  • 标志(Flags):在 Intent 类中定义的、充当 Intent 元数据的标志。标志可以指示 Android 系统如何启动
    Activity(例如,Activity 应属于哪个Task )。

Intent 解析

当系统收到隐式 Intent 以启动 Activity 时,它根据以下三个方面将该 Intent 与 Intent 过滤器进行比较,搜索该Intent 的最佳 Activity:

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

系统通过将 Intent 与所有这三个元素进行比较,根据过滤器测试隐式 Intent。隐式 Intent 若要传递给组件,必须通过所有这三项测试。如果 Intent 甚至无法匹配其中任何一项测试,则 Android 系统不会将其传递给组件。但是,由于一个组件可能有多个 Intent 过滤器,因此未能通过某一组件过滤器的 Intent 可能会通过另一过滤器。(在Demo中实验了几次,发现 Action 和 Data 必须至少设置一个,否则不能匹配到)

操作(Action)匹配

要指定接受的 Intent 操作, Intent 过滤器既可以不声明任何 action 元素,也可以声明多个此类元素。例如:




...

要通过此过滤器,您在 Intent 中指定的操作必须与过滤器中列出的 某一操作匹配。
如果该过滤器未列出任何操作,则 Intent 没有任何匹配项,因此所有 Intent 均无法通过测试。但是,如果 Intent 未指定操作,则会通过测试(只要过滤器至少包含一个操作)。

类别(Category)匹配

要指定接受的 Intent 类别, Intent 过滤器既可以不声明任何 category 元素,也可以声明多个此类元素。例如:




...

若要 Intent 通过类别测试,则 Intent 中的每个类别均必须与过滤器中的类别匹配。反之则未必然,Intent 过滤器声明的类别可以超出 Intent 中指定的数量,且 Intent 仍会通过测试。因此,不含类别的 Intent 应当始终会通过此测试,无论过滤器中声明何种类别均是如此。

Android 会自动将 CATEGORY_DEFAULT 类别应用于传递给 startActivity() 和 startActivityForResult() 的所有隐式 Intent。因此,如需 Activity 接收隐式 Intent,则必须将 " android.intent.category.DEFAULT " 的类别包括在其 Intent 过滤器中。

数据(Data)匹配

要指定接受的 Intent 数据, Intent 过滤器既可以不声明任何 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 。上述每
个属性均为可选,但存在线性依赖关系:

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

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

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

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

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

  • 仅当过滤器未指定任何 URI 或 MIME 类型时,不含 URI 和 MIME 类型的 Intent 才会通过测试。
  • 对于包含 URI、但不含 MIME 类型(既未显式声明,也无法通过 URI 推断得出)的 Intent,仅当其 URI 与过滤器的 URI 格式匹配、且过滤器同样未指定 MIME 类型时,才会通过测试。
  • 仅当过滤器列出相同的 MIME 类型且未指定 URI 格式时,包含 MIME 类型、但不含 URI 的 Intent 才会通过测试。
  • 仅当 MIME 类型与过滤器中列出的类型匹配时,包含 URI 和 MIME 类型(通过显式声明,或可以通过 URI 推断得出)的 Intent 才会通过测试的 MIME 类型部分。如果 Intent 的 URI 与过滤器中的 URI 匹配,或者如果
    Intent 具有 content: 或 file: URI 且过滤器未指定 URI,则 Intent 会通过测试的 URI 部分。换而言之,如
    果过滤器仅列出 MIME 类型,则假定组件支持 content: 和 file: 数据。

最后一条规则,反映了期望组件能够从文件中或 内容提供者 处获得本地数据。因此,其过滤器可以仅列出数据类型,而不必显式命名 content: 和 file: 架构。这是一个典型的案例。例如,下文中的 data 元素向 Android 指出,组件可从 内容提供者 处获得并显示图像数据。



...

Intent 匹配

您的应用可以采用类似的方式使用 Intent 匹配。 PackageManager 提供了一整套 query...() 方法来返回所有能够接受特定 Intent 的组件。此外,它还提供了一系列类似的 resolve...() 方法来确定响应 Intent 的最佳组件。例如, queryIntentActivities() 将返回能够执行那些作为参数传递的 Intent 的所有 Activity 列表,而
queryIntentServices() 则可返回类似的服务列表。这两种方法均不会激活组件,而只是列出能够响应的组件。对于广播接收器,有一种类似的方法: queryBroadcastReceivers() 。

你可能感兴趣的:(【Android】你可能需要了解Intent的那些事)