Intent 和 Intent 过滤器
Intent 是 Android 中用于组件间通信的核心机制。它不仅可以启动 Activity、Service,还可以发送广播消息。理解 Intent 是掌握 Android 开发的关键。
什么是 Intent?
Intent 是一个消息传递对象,用于请求其他应用组件执行操作。它可以:
- 启动 Activity(打开新界面)
- 启动 Service(启动后台服务)
- 发送广播(传递系统或应用事件)
Intent 的两种类型
1. 显式 Intent
明确指定要启动的组件类名,用于应用内部组件跳转。
// 显式启动 Activity
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
// 显式启动 Service
val serviceIntent = Intent(this, MyService::class.java)
startService(serviceIntent)
2. 隐式 Intent
不指定具体组件,而是通过 Action、Category、Data 等属性让系统匹配合适的组件。
// 隐式打开网页
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://www.example.com")
}
startActivity(intent)
// 隐式发送邮件
val emailIntent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_EMAIL, arrayOf("[email protected]"))
putExtra(Intent.EXTRA_SUBJECT, "邮件主题")
putExtra(Intent.EXTRA_TEXT, "邮件内容")
}
startActivity(emailIntent)
Intent 的核心属性
Action
表示要执行的动作,是字符串常量。
// 常用系统 Action
val actions = mapOf(
Intent.ACTION_VIEW to "查看数据",
Intent.ACTION_SEND to "发送数据",
Intent.ACTION_CALL to "拨打电话",
Intent.ACTION_DIAL to "打开拨号界面",
Intent.ACTION_SENDTO to "发送消息",
Intent.ACTION_PICK to "选择数据",
Intent.ACTION_GET_CONTENT to "获取内容"
)
Data
要操作的数据 URI。
// 打开网页
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://www.example.com")
}
// 拨打电话
val callIntent = Intent(Intent.ACTION_DIAL).apply {
data = Uri.parse("tel:1234567890")
}
// 发送短信
val smsIntent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("smsto:1234567890")
}
Category
额外的类别信息,用于进一步筛选组件。
// 常用 Category
val categories = mapOf(
Intent.CATEGORY_DEFAULT to "默认",
Intent.CATEGORY_BROWSABLE to "可通过浏览器访问",
Intent.CATEGORY_LAUNCHER to "应用入口",
Intent.CATEGORY_HOME to "主屏幕"
)
Extras
携带的额外数据,使用键值对存储。
val intent = Intent(this, DetailActivity::class.java).apply {
// 传递基本类型
putExtra("user_id", 123)
putExtra("user_name", "张三")
putExtra("is_vip", true)
// 传递 Serializable 对象
putExtra("user", userObject)
// 传递 Parcelable 对象(推荐,性能更好)
putExtra("product", productObject)
// 传递 Bundle
putExtras(bundle)
}
startActivity(intent)
Flags
控制 Intent 的行为和启动模式。
val intent = Intent(this, MainActivity::class.java).apply {
// 清除 Activity 栈,创建新任务
flags = Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK
// 或者单独设置
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
在 Activity 中接收 Intent 数据
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
// 获取传递的数据
val userId = intent.getIntExtra("user_id", -1)
val userName = intent.getStringExtra("user_name")
val isVip = intent.getBooleanExtra("is_vip", false)
// 获取 Parcelable 对象
val product = intent.getParcelableExtra<Product>("product")
// 获取 Serializable 对象
val user = intent.getSerializableExtra("user") as? User
// 使用数据
displayUserInfo(userId, userName, isVip)
}
}
Intent 过滤器(Intent Filter)
Intent Filter 在 AndroidManifest.xml 中声明,用于指定组件可以响应的 Intent 类型。
Activity 的 Intent Filter
<activity android:name=".ShareActivity">
<!-- 主入口 -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 分享文本 -->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<!-- 分享图片 -->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<!-- 打开特定链接 -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="www.example.com"
android:pathPrefix="/product" />
</intent-filter>
</activity>
处理接收到的隐式 Intent
class ShareActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_share)
when (intent.action) {
Intent.ACTION_SEND -> {
when (intent.type) {
"text/plain" -> handleTextShare()
"image/*" -> handleImageShare()
}
}
Intent.ACTION_VIEW -> handleDeepLink()
}
}
private fun handleTextShare() {
val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
// 处理分享的文本
}
private fun handleImageShare() {
val imageUri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
// 处理分享的图片
}
private fun handleDeepLink() {
val data = intent.data
val productId = data?.getQueryParameter("id")
// 处理深度链接
}
}
检查 Intent 是否可处理
在启动隐式 Intent 前,应该检查是否有应用可以处理它。
fun openWebPage(url: String, context: Context) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
// 检查是否有应用可以处理
if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent)
} else {
Toast.makeText(context, "没有应用可以打开此链接", Toast.LENGTH_SHORT).show()
}
}
使用 Intent 选择器
当多个应用可以处理同一个 Intent 时,可以让用户选择。
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "分享这段文字")
}
// 创建选择器,设置标题
val chooser = Intent.createChooser(intent, "分享到")
// 检查是否有应用可以处理
if (intent.resolveActivity(packageManager) != null) {
startActivity(chooser)
}
PendingIntent
PendingIntent 是一种特殊的 Intent,允许其他应用或系统在未来某个时刻执行操作。
// 创建用于通知的 PendingIntent
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
0,
notificationIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
// 创建用于小部件的 PendingIntent
val widgetIntent = Intent(this, MyWidgetProvider::class.java).apply {
action = "ACTION_REFRESH"
}
val widgetPendingIntent = PendingIntent.getBroadcast(
this,
0,
widgetIntent,
PendingIntent.FLAG_IMMUTABLE
)
// 用于闹钟
val alarmIntent = PendingIntent.getBroadcast(
this,
0,
Intent(this, AlarmReceiver::class.java),
PendingIntent.FLAG_IMMUTABLE
)
最佳实践
1. 使用常量定义 Extra 键
object IntentExtras {
const val USER_ID = "user_id"
const val USER_NAME = "user_name"
const val PRODUCT = "product"
}
// 使用
intent.putExtra(IntentExtras.USER_ID, 123)
2. 提供静态工厂方法
class DetailActivity : AppCompatActivity() {
companion object {
fun newIntent(context: Context, userId: Int, userName: String): Intent {
return Intent(context, DetailActivity::class.java).apply {
putExtra(IntentExtras.USER_ID, userId)
putExtra(IntentExtras.USER_NAME, userName)
}
}
}
// ...
}
// 使用
startActivity(DetailActivity.newIntent(this, 123, "张三"))
3. 使用 Parcelable 代替 Serializable
// 使用 @Parcelize 注解(推荐)
@Parcelize
data class Product(
val id: Int,
val name: String,
val price: Double
) : Parcelable
// 传统方式
class ProductTraditional(
val id: Int,
val name: String,
val price: Double
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString() ?: "",
parcel.readDouble()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeString(name)
parcel.writeDouble(price)
}
override fun describeContents(): Int = 0
companion object CREATOR : Parcelable.Creator<ProductTraditional> {
override fun createFromParcel(parcel: Parcel): ProductTraditional {
return ProductTraditional(parcel)
}
override fun newArray(size: Int): Array<ProductTraditional?> {
return arrayOfNulls(size)
}
}
}
4. 安全地处理 Intent 数据
class SafeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 安全获取数据,提供默认值
val userId = intent.getIntExtra("user_id", -1)
if (userId == -1) {
// 处理无效数据
finish()
return
}
// 使用 requireNotNull 处理可空类型
val userName = requireNotNull(intent.getStringExtra("user_name")) {
"user_name is required"
}
}
}
小结
- 显式 Intent:明确指定目标组件,用于应用内部跳转
- 隐式 Intent:通过 Action、Data、Category 匹配组件
- Intent Filter:声明组件可以响应的 Intent 类型
- PendingIntent:延迟执行的 Intent,用于通知、小部件等
- 最佳实践:使用常量定义键、提供工厂方法、安全处理数据
练习
- 创建一个 Activity,使用显式 Intent 跳转到另一个 Activity 并传递数据
- 实现分享功能,接收其他应用分享的文本和图片
- 配置深度链接,通过 URL 打开应用的特定页面
- 创建一个通知,点击后跳转到指定 Activity