Android必读之Intent 和 Intent 过滤器

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

  • 启动 ActivityActivity 表示应用中的一个屏幕。通过将 Intent 传递给 startActivity(),您可以启动新的 Activity 实例。Intent 描述了要启动的 Activity,并携带了任何必要的数据。如果您希望在 Activity 完成后收到结果,请调用 startActivityForResult()。在 Activity 的onActivityResult() 回调中,您的 Activity 将结果作为单独的 Intent 对象接收。如需了解详细信息,请参阅 Activity 指南。
  • 启动服务Service 是一个不使用用户界面而在后台执行操作的组件。通过将 Intent 传递给 startService(),您可以启动服务执行一次性操作(例如,下载文件)。Intent 描述了要启动的服务,并携带了任何必要的数据。如果服务旨在使用客户端-服务器接口,则通过将 Intent 传递给 bindService(),您可以从其他组件绑定到此服务。如需了解详细信息,请参阅服务指南。
  • 传递广播:广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将Intent 传递给 sendBroadcast()sendOrderedBroadcast() 或 sendStickyBroadcast(),您可以将广播传递给其他应用。

Intent 类型

Intent 分为两种类型:

  • 显式 Intent:按名称(完全限定类名)指定要启动的组件。 通常,您会在自己的应用中使用显式 Intent 来启动组件,这是因为您知道要启动的 Activity 或服务的类名。例如,启动新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
  • 隐式 Intent :不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。 例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。

创建显式 Intent 启动 Activity 或服务时,系统将立即启动 Intent 对象中指定的应用组件。《Android必读之Intent 和 Intent 过滤器》

图 1. 隐式 Intent 如何通过系统传递以启动其他 Activity 的图解:[1] Activity A 创建包含操作描述的 Intent,并将其传递给 startActivity()[2] Android 系统搜索所有应用中与 Intent 匹配的 Intent 过滤器。 找到匹配项之后,[3] 该系统通过调用匹配 Activity(Activity B)的 onCreate() 方法并将其传递给 Intent,以此启动匹配 Activity。

创建隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件(AndroidMnifest.xml)中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。 如果 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并向其传递 Intent对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。
Intent 过滤器是应用清单文件中的一个表达式,它指定该组件要接收的 Intent 类型。 例如,通过为 Activity 声明 Intent 过滤器,您可以使其他应用能够直接使用某一特定类型的 Intent 启动 Activity。同样,如果您没有为 Activity 声明任何 Intent 过滤器,则 Activity 只能通过显式 Intent 启动。

注意:为了确保应用的安全性,启动 Service 时,请始终使用显式 Intent,且不要为服务声明 Intent 过滤器。使用隐式 Intent 启动服务存在安全隐患,因为您无法确定哪些服务将响应 Intent,且用户无法看到哪些服务已启动。从 Android 5.0(API 级别 21)开始,如果使用隐式 Intent 调用 bindService(),系统会引发异常。

显式 Intent 示例

显式 Intent 是指用于启动某个特定应用组件(例如,应用中的某个特定 Activity 或服务)的 Intent。 要创建显式 Intent,请为 Intent 对象定义组件名称 — Intent 的所有其他属性均为可选属性。
例如,如果在应用中构建了一个名为 DownloadService、旨在从网页下载文件的服务,则可使用以下代码启动该服务:

// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

隐式 Intent 示例

隐式 Intent 指定能够在可以执行相应操作的设备上调用任何应用的操作。 如果您的应用无法执行该操作而其他应用可以,且您希望用户选取要使用的应用,则使用隐式 Intent 非常有用。
例如,如果您希望用户与他人分享您的内容,请使用 ACTION_SEND 操作创建 Intent,并添加指定共享内容的 extra。 使用该 Intent 调用 startActivity() 时,用户可以选取共享内容所使用的应用。

// Create the text message with a string
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) {
    startActivity(sendIntent);
}
注意:用户可能没有任何应用处理您发送到 startActivity() 的隐式 Intent。如果出现这种情况,则调用将会失败,且应用会崩溃。要验证 Activity 是否会接收 Intent,请对 Intent 对象调用 resolveActivity()。如果结果为非空,则至少有一个应用能够处理该 Intent,且可以安全调用 startActivity()。 如果结果为空,则不应使用该 Intent。如有可能,您应停用发出该 Intent 的功能。

调用 startActivity() 时,系统将检查已安装的所有应用,确定哪些应用能够处理这种 Intent(即:含 ACTION_SEND 操作并携带“text/plain”数据的 Intent )。 如果只有一个应用能够处理,则该应用将立即打开并为其提供 Intent。 如果多个 Activity 接受 Intent,则系统将显示一个对话框,使用户能够选取要使用的应用。

强制使用应用选择器

如果有多个应用响应隐式 Intent,则用户可以选择要使用的应用,并将其设置为该操作的默认选项。 如果用户可能希望今后一直使用相同的应用执行某项操作(例如,打开网页时,用户往往倾向于仅使用一种网络浏览器),则这一点十分有用。
但是,如果多个应用可以响应 Intent,且用户可能希望每次使用不同的应用,则应采用显式方式显示选择器对话框。 选择器对话框每次都会要求用户选择用于操作的应用(用户无法为该操作选择默认应用)。 例如,当应用使用 ACTION_SEND 操作执行“共享”时,用户根据目前的状况可能需要使用另一不同的应用,因此应当始终使用选择器对话框,如图 2 中所示。《Android必读之Intent 和 Intent 过滤器》
要显示选择器,请使用 createChooser() 创建 Intent,并将其传递给 startActivity()。例如:

Intent sendIntent = new Intent(Intent.ACTION_SEND);
...
// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser = Intent.createChooser(sendIntent, title);
// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

这将显示一个对话框,其中有响应传递给 createChooser() 方法的 Intent 的应用列表,并且将提供的文本用作对话框标题。

点赞

发表评论