Android 最重要的功能之一是应用能够根据其希望执行的“操作”将用户发送到另一个应用。例如,如果您的应用有您想在地图上显示的商家地址,您无需在应用中构建一个显示地图的 Activity。相反,您可以创建一个使用 Intent
查看该地址的请求。然后,Android 系统会启动一个能够在地图上显示该地址的应用。
正如第一堂课《构建您的第一个应用》中所述,您必须使用 Intent 在您自己的应用中的 Activity 之间进行导航。您通常使用“显式 Intent”来执行此操作,它定义了您要启动的组件的确切类名。但是,当您希望单独的应用执行某个操作(例如“查看地图”)时,您必须使用“隐式 Intent”。
本课将向您展示如何为特定操作创建隐式 Intent,以及如何使用它来启动在另一个应用中执行该操作的 Activity。另请参阅此处嵌入的视频,以了解为何为隐式 Intent 添加运行时检查非常重要。
构建隐式 Intent
隐式 Intent 不声明要启动的组件的类名,而是声明要执行的操作。该操作指定您要执行的操作,例如“查看”、“编辑”、“发送”或“获取”某些内容。
将 Intent 操作与数据关联
Intent 通常还包含与操作关联的数据,例如您要查看的地址或要发送的电子邮件。根据您要创建的 Intent,数据可以是 Uri
、其他几种数据类型之一,或者 Intent 可能根本不需要数据。
如果您的数据是 Uri
,则可以使用一个简单的 Intent()
构造函数来定义操作和数据。
例如,以下是使用 Uri
数据指定电话号码以发起电话呼叫的 Intent 的创建方式:
Kotlin
val callIntent: Intent = Uri.parse("tel:5551234").let { number -> Intent(Intent.ACTION_DIAL, number) }
Java
Uri number = Uri.parse("tel:5551234"); Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
当您的应用通过调用 startActivity()
调用此 Intent 时,“电话”应用会向给定的电话号码发起呼叫。
以下是其他一些 Intent 及其操作和 Uri
数据对:
查看地图
Kotlin
// Map point based on address val mapIntent: Intent = Uri.parse( "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California" ).let { location -> // Or map point based on latitude/longitude // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level Intent(Intent.ACTION_VIEW, location) }
Java
// Map point based on address Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); // Or map point based on latitude/longitude // Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
查看网页
Kotlin
val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage -> Intent(Intent.ACTION_VIEW, webpage) }
Java
Uri webpage = Uri.parse("https://www.android.com"); Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
向 Intent 添加额外数据
其他类型的隐式 Intent 需要“额外”数据,这些数据提供不同的数据类型,例如字符串。您可以使用各种 putExtra()
方法添加一个或多个额外数据。
默认情况下,系统会根据包含的 Uri
数据确定 Intent 所需的适当 MIME 类型。如果您在 Intent 中不包含 Uri
,则通常应使用 setType()
指定与 Intent 关联的数据类型。设置 MIME 类型会进一步指定哪些 Activity 应接收该 Intent。
以下是一些添加额外数据以指定所需操作的 Intent:
发送带附件的电子邮件
Kotlin
Intent(Intent.ACTION_SEND).apply { // The intent does not have a URI, so declare the "text/plain" MIME type type = "text/plain" putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients putExtra(Intent.EXTRA_SUBJECT, "Email subject") putExtra(Intent.EXTRA_TEXT, "Email message text") putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment")) // You can also attach multiple items by passing an ArrayList of Uris }
Java
Intent emailIntent = new Intent(Intent.ACTION_SEND); // The intent does not have a URI, so declare the "text/plain" MIME type emailIntent.setType(HTTP.PLAIN_TEXT_TYPE); emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject"); emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text"); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment")); // You can also attach multiple items by passing an ArrayList of Uris
创建日历事件
注意:此日历事件 Intent 仅支持 API 级别 14 及更高版本。
Kotlin
// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM. Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply { val beginTime: Calendar = Calendar.getInstance().apply { set(2021, 0, 23, 7, 30) } val endTime = Calendar.getInstance().apply { set(2021, 0, 23, 10, 30) } putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis) putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis) putExtra(Events.TITLE, "Ninja class") putExtra(Events.EVENT_LOCATION, "Secret dojo") }
Java
// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM. Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); Calendar beginTime = Calendar.getInstance(); beginTime.set(2021, 0, 23, 7, 30); Calendar endTime = Calendar.getInstance(); endTime.set(2021, 0, 23, 10, 30); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); calendarIntent.putExtra(Events.TITLE, "Ninja class"); calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
注意:请务必尽可能具体地定义您的 Intent
。例如,如果您想使用 ACTION_VIEW
Intent 显示图像,您应该指定 MIME 类型为 image/*
。这可以防止能够“查看”其他类型数据(例如地图应用)的应用被该 Intent 触发。
通过 Intent 启动 Activity
创建 Intent
并设置额外信息后,调用 startActivity()
将其发送到系统:
Kotlin
startActivity(intent)
Java
startActivity(intent);
处理没有应用可以接收 Intent 的情况
尽管许多 Intent 都可以由设备上安装的其他应用(例如电话、电子邮件或日历应用)成功处理,但您的应用应为没有 Activity 可以处理您的应用 Intent 的情况做好准备。每当您调用 Intent 时,都应准备好捕获 ActivityNotFoundException
,如果没有任何其他 Activity 可以处理您的应用 Intent,则会发生此异常:
Kotlin
try { startActivity(intent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
try { startActivity(intent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
捕获此异常后,决定您的应用接下来应该做什么。下一步取决于您尝试调用的 Intent 的具体特征。例如,如果您知道有某个特定应用可以处理该 Intent,则为用户提供下载该应用的链接。详细了解如何链接到您在 Google Play 上的产品。
消歧对话框
如果系统识别出多个 Activity 可以处理该 Intent,它会显示一个对话框(有时称为“消歧对话框”),供用户选择要使用的应用,如图 1 所示。如果只有一个 Activity 处理该 Intent,系统会立即启动它。

图 1. 当多个应用可以处理 Intent 时出现的选择对话框示例。
完整示例
以下是一个完整示例,展示了如何创建 Intent 以查看地图,验证是否存在处理该 Intent 的应用,然后启动它:
Kotlin
// Build the intent. val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California") val mapIntent = Intent(Intent.ACTION_VIEW, location) // Try to invoke the intent. try { startActivity(mapIntent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
// Build the intent. Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); // Try to invoke the intent. try { startActivity(mapIntent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
显示应用选择器

图 2. 一个选择器对话框。
请注意,当您通过将 Intent
传递给 startActivity()
来启动 Activity,并且有多个应用响应 Intent 时,用户可以选择默认使用哪个应用(通过选中对话框底部的复选框;参见图 1)。当执行某个操作时,用户通常每次都希望使用相同的应用,例如打开网页(用户可能只使用一个网络浏览器)或拍照(用户可能更喜欢一个相机),这非常有用。
但是,如果待执行的操作可以由多个应用处理,并且用户每次可能偏好不同的应用(例如“共享”操作,用户可能通过多个应用共享一个项目),您应该明确显示一个选择器对话框,如图 2 所示。选择器对话框会强制用户每次都选择用于该操作的应用(用户不能为该操作选择默认应用)。
要显示选择器,请使用 createChooser()
创建一个 Intent
,并将其传递给 startActivity()
。例如:
Kotlin
val intent = Intent(Intent.ACTION_SEND) // Create intent to show chooser val chooser = Intent.createChooser(intent, /* title */ null) // Try to invoke the intent. try { startActivity(chooser) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
Intent intent = new Intent(Intent.ACTION_SEND); // Create intent to show chooser Intent chooser = Intent.createChooser(intent, /* title */ null); // Try to invoke the intent. try { startActivity(chooser); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
这会显示一个对话框,其中包含响应传递给 createChooser()
方法的 Intent 的应用列表。如果操作不是 ACTION_SEND
或 ACTION_SEND_MULTIPLE
,则可以提供 title
参数。