Intent 基础
本教程共 100 篇 · 第 29 篇 · 更新于 2026-07-28 · 约 8 分钟阅读
29. Intent 基础
本节目标:理解 Intent 是什么、显式和隐式 Intent 的区别、Intent 的六大组成部分,会用 Intent 启动组件和传递数据。
Intent 是什么
Intent(意图)是 Android 组件之间通信的消息对象。它描述「我想干一件事」,由系统负责找到合适的组件来处理。
三大用途:
- 启动 Activity:
startActivity(intent)。 - 启动 Service:
startService(intent)或bindService(intent, ...)。 - 发送广播:
sendBroadcast(intent)。
两种 Intent
显式 Intent
明确指定要启动的组件(类名)。系统直接启动它,不问别人。
val intent = Intent(this, DetailActivity::class.java)
startActivity(intent)
适用:启动自己应用内的组件,你知道确切类名。
隐式 Intent
不指定具体组件,而是声明「我想做什么」(action)和「对什么数据做」(data),让系统找能处理的组件。
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
startActivity(intent)
系统在所有应用的 Manifest 里找声明了能处理 ACTION_VIEW + https 数据的 Activity,找到多个就弹选择框让用户选。
适用:调用系统功能(打开网页、拨号、分享)或让其他应用处理。
Warning
- 启动 Service 必须用显式 Intent。Android 5.0 起隐式 Intent 启动 Service 会抛异常。安全考虑:你不知道哪个 Service 会响应。
Intent 的六大组成部分
一个 Intent 能携带这些信息:
1. Component Name(组件名)
目标组件的完整类名。有它就是显式 Intent,没有就是隐式。
intent.setClass(this, DetailActivity::class.java)
// 或构造时传
Intent(this, DetailActivity::class.java)
2. Action(动作)
描述要做什么的字符串。系统定义了很多常量:
| Action | 含义 |
|---|---|
ACTION_VIEW | 查看数据(打开网页、看图片) |
ACTION_DIAL | 拨号面板 |
ACTION_CALL | 直接拨打电话(要权限) |
ACTION_SEND | 分享/发送数据 |
ACTION_EDIT | 编辑数据 |
ACTION_PICK | 选择数据(联系人、图片) |
ACTION_MAIN | 应用入口 |
ACTION_SYNC | 同步数据 |
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
自定义 action 加包名前缀避免冲突:"com.example.action.MY_ACTION"。
3. Data(数据)
操作的对象,通常是 URI + MIME 类型。
// 网页 URL
Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
// 地理坐标
Intent(Intent.ACTION_VIEW, Uri.parse("geo:39.9,116.4"))
// 电话号码
Intent(Intent.ACTION_DIAL, Uri.parse("tel:10086"))
// 联系人
Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
URI scheme(https、tel、geo、content、file)决定系统找哪类组件。
4. Category(类别)
额外描述组件类型的信息。常用:
CATEGORY_LAUNCHER:桌面启动入口。CATEGORY_DEFAULT:默认类别,隐式 Intent 必须匹配。CATEGORY_BROWSABLE:能从浏览器/网页调起。
intent.addCategory(Intent.CATEGORY_BROWSABLE)
5. Extras(附加数据)
键值对数据,第 28 章讲过。
intent.putExtra("user_id", 1001L)
intent.putExtra("user_name", "张三")
6. Flags(标志位)
控制启动行为,第 27 章讲过(FLAG_ACTIVITY_NEW_TASK 等)。
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
显式 Intent 实战
// 启动 Activity
val intent = Intent(context, DetailActivity::class.java).apply {
putExtra("user_id", userId)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
context.startActivity(intent)
// 启动 Service(前台服务,Android 8+)
val intent = Intent(context, DownloadService::class.java).apply {
putExtra("url", downloadUrl)
}
ContextCompat.startForegroundService(context, intent)
// 发送广播
val intent = Intent("com.example.ACTION_DATA_UPDATED").apply {
putExtra("count", newCount)
}
context.sendBroadcast(intent)
隐式 Intent 实战
打开网页
val url = "https://developer.android.com"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
拨号
val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:10086"))
startActivity(intent)
Note
ACTION_DIAL只打开拨号面板,不直接拨出。ACTION_CALL直接拨号但要CALL_PHONE危险权限。
分享文本
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "快来看这个应用:https://example.com")
putExtra(Intent.EXTRA_SUBJECT, "推荐")
}
startActivity(Intent.createChooser(intent, "分享到"))
Intent.createChooser 强制弹选择框,即使只有一个目标。
选择图片
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
type = "image/*"
}
startActivityForResult... // 用 Activity Result API
现代写法用 Activity Result API:
val pickImage = registerForActivityResult(
ActivityResultContracts.GetContent()
) { uri: Uri? ->
uri?.let { showImage(it) }
}
pickImage.launch("image/*")
检查是否有组件能处理
隐式 Intent 可能找不到能处理的组件,直接 startActivity 会崩。先检查:
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
Toast.makeText(this, "没有应用能打开网页", Toast.LENGTH_SHORT).show()
}
Warning
- Android 11+(API 30)起,
resolveActivity对其他应用的 Activity 默认返回 null(包可见性限制)。要在 Manifest 声明<queries>才能查到:
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
</queries>
PendingIntent
PendingIntent 是「延迟执行的 Intent」,把 Intent 的执行权交给别人。别人在某个时刻触发它,相当于你代为执行。
常见用途:
- 通知点击:
NotificationCompat.Builder.setContentIntent(pendingIntent)。 - 桌面小部件点击。
- AlarmManager 定时任务。
val intent = Intent(context, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("新消息")
.setContentText("点击查看")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.build()
Warning
- Android 12+(API 31)起,PendingIntent 必须指定
FLAG_IMMUTABLE或FLAG_MUTABLE。不指定会崩。大多数场景用FLAG_IMMUTABLE(不可变,更安全)。
Intent 与 Compose
Compose 里启动外部 Activity 仍用 Intent,但配合 LocalContext:
@Composable
fun ShareButton(text: String) {
val context = LocalContext.current
Button(onClick = {
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, text)
}
context.startActivity(Intent.createChooser(intent, "分享"))
}) {
Text("分享")
}
}
小结
Intent 是组件通信的消息对象。显式 Intent 指定类名,启动自己的组件;隐式 Intent 声明 action + data,让系统找能处理的组件。六大组成:Component、Action、Data、Category、Extra、Flag。隐式 Intent 要检查能否处理,Android 11+ 要声明 <queries>。PendingIntent 用于通知、小部件、定时任务,Android 12+ 要指定可变性 flag。下一节学 Intent Filter。