一文带你吃透Android Intent




Intent 和 Intent 过滤器

Intent是消息传递对象,我们可以用来从其他组件请求操作,Intent可以通过多种方式促进组件之间的通信,但是主要的使用方式有以下三种:

  • 启动Activity【startActivity(Intent intent)
  • 启动Service【startService(Intent intent)
  • 启动广播【sendBroadCast(Intent intent)】【sendBroadOrderedCast(Intent intent)


Intent类型

Intent分为两种类型

  • 显示Intent

通过提供完整的应用报名或者完全限定的组件类名来指定可处理Intent的应用。

  • 隐式Intent

不会指定特定的组件,而是声明要执行的特定操作。

使用隐式Intent时,Android系统会将Intent中的内容与设备上其他应用的清单文件中声明的Intent过滤器进行比较,从而找到要启动的相应组件,如果匹配,则会启动该组件,并向其传递Intent对象,如果有多个过滤器匹配则显示对话框,支持用户选择想要使用的应用。如果该intent没有申明任何过滤器这只能通过显示intent启动。

注意:尽量不要使用隐式intent启动服务,因为用户不知道启动了哪些服务。




构建Intent

Intent对象可以设置以下信息

  • 组件名称

设置要启动组件的名称,当设置该属性之后,该Intent只能启动对应的组件,如果没有设置组件名称,则为隐式Intent,可以使用 setComponent()setClass()setClassName(),或 Intent 构造函数设置组件名称。

  • 操作

指定要执行的通用操作,可以使用setAction函数为Intent指定操作。如ACTION_VIEWACTION_SEND

  • 数据

引用待操作数据和/或该数据 MIME 类型的 URI(Uri 对象)。提供的数据类型通常由 Intent 的操作决定。例如,如果操作是 ACTION_EDIT,则数据应包含待编辑文档的 URI

  • 类别

一个包含应处理 Intent 组件类型的附加信息的字符串。可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。以下是一些常见类别:

  • CATEGORY_BROWSABLE
    目标 Activity 允许本身通过网络浏览器启动,以显示链接引用的数据,如图像或电子邮件。
  • CATEGORY_LAUNCHER
    该 Activity 是任务的初始 Activity,在系统的应用启动器中列出。

可以使用setCateGory()添加类别。

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

  • Extra
    可以使用各种 putExtra() 方法添加 extra 数据,每种方法均接受两个参数:键名和值。还可以创建一个包含所有 extra 数据的 Bundle 对象,然后使用 putExtras() 将 Bundle 插入 Intent 中。

  • 标志
    可以用来指定启动目标组件的方式,如:
    FLAG_ACTIVITY_SINGLE_TOP(相当于设置为SingleTop模式)




显示Intent

Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
//显示启动服务
startService(downloadIntent);





隐式Intent

Intent sendIntent = new Intent();
//执行操作
sendIntent.setAction(Intent.ACTION_SEND);
//携带数据
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
//设置数据类型
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
//为了确保当没有匹配的intent-fliter时,不会出现异常
    startActivity(sendIntent);
}





强制使用应用选择器

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 过滤器。每个 Intent 过滤器均根据 Intent 的操作、数据和类别指定自身接受的 Intent 类型。仅当隐式 Intent 可以通过 Intent 过滤器之一传递时,系统才会将该 Intent 传递给应用组件。
可以使用以下三个元素中的一个或多个指定要接受的 Intent 类型

  • <action>
    在 name 属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。
  • <data>
    使用一个或多个指定数据 URI(scheme、host、port、path)各个方面和 MIME 类型的属性,声明接受的数据类型。
  • <categroy>
    在 name 属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。




过滤器示例

<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>

可以创建一个包括多个 、 或 实例的过滤器。创建时,需确定组件能够处理这些过滤器元素的任何及所有组合。

如需仅以操作、数据和类别类型的特定组合来处理多种 Intent,则需创建多个 Intent 过滤器。

系统通过将 Intent 与所有这三个元素进行比较,根据过滤器测试隐式 Intent。隐式 Intent 若要传递给组件,必须通过所有这三项测试。如果 Intent 甚至无法匹配其中任何一项测试,则 Android 系统不会将其传递给组件。但是,由于一个组件可能有多个 Intent 过滤器,因此未能通过某一组件过滤器的 Intent 可能会通过另一过滤器。




Intent解析

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

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

下文根据应用的清单文件中的 Intent 过滤器声明,描述 Intent 如何与相应的组件匹配。




操作测试

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

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

要通过此过滤器,您在 Intent 中指定的操作必须与过滤器中列出的某一操作匹配。

如果该过滤器未列出任何操作,则 Intent 没有任何匹配项,因此所有 Intent 均无法通过测试。但是,如果 Intent 未指定操作,则只要过滤器内包含至少一项操作,就可以通过测试。




类别测试

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

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

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



数据测试

要指定接受的 Intent 数据,Intent 过滤器既可以不声明任何 元素,也可以声明多个此类元素,如下例所示:

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

猜你喜欢

转载自blog.csdn.net/weixin_43927892/article/details/105372864