PendingIntent
是 Android 框架中非常重要的组成部分,但是目前大多数与该主题相关的开发者资源更关注它的实现细节,即 "PendingIntent 是由系统维护的 token 引用",而忽略了它的用途。
由于 Android 12 对 PendingIntent 进行了 重要更新 ,包括需要显式确定 PendingIntent 是否是可变的,所以我认为有必要和大家深入聊聊 PendingIntent 有什么作用,系统如何使用它,以及为什么您会需要可变类型的 PendingIntent。
PendingIntent 是什么?
PendingIntent 对象封装了 Intent 对象的功能,同时以您应用的名义指定其他应用允许哪些操作的执行,来响应用户未来会进行的操作。比如,所封装的 Intent 可能会在闹铃关闭后或者用户点击通知时被触发。
PendingIntent 的关键点是其他应用在触发 intent 时是 以您应用的名义 。换而言之,其他应用会使用您应用的身份来触发 intent。
为了让 PendingIntent 具备和普通 Intent 一样的功能,系统会使用创建 PendingIntent 时的身份来触发它。在大多数情况下,比如闹铃和通知,其中所用到的身份就是应用本身。
我们来看应用中使用 PendingIntent 的不同方式,以及我们使用这些方式的原因。
常规用法
使用
PendingIntent
最常规最基础的用法是作为关联某个通知所进行的操作。
val intent = Intent(applicationContext, MainActivity::class.java).apply {
action = NOTIFICATION_ACTION
data = deepLink
}
val pendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_REQUEST_CODE,
intent,
PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(
applicationContext,
NOTIFICATION_CHANNEL
).apply {
// ...
setContentIntent(pendingIntent)
// ...
}.build()
notificationManager.notify(
NOTIFICATION_TAG,
NOTIFICATION_ID,
notification
)
复制代码
可以看到我们构建了一个标准类型的
Intent
来打开我们的应用,然后,在添加到通知之前简单用
PendingIntent
封装了一下。
在本例中,由于我们明确知道未来需要进行的操作,所以我们使用
FLAG_IMMUTABLE
标记构建了无法被修改的
PendingIntent
。
调用
NotificationManagerCompat.notify()
之后工作就完成了。当系统显示通知,且用户点击通知时,会在我们的
PendingIntent
上调用
PendingIntent.send()
,来启动我们的应用。
更新不可变的 PendingIntent
您也许会认为如果应用需要更新
PendingIntent
,那么它需要是可变类型,但其实并不是。应用所创建的
PendingIntent
可通过
FLAG_UPDATE_CURRENT
标记来更新。
val updatedIntent = Intent(applicationContext, MainActivity::class.java).apply {
action = NOTIFICATION_ACTION
data = differentDeepLink
}
// 由于我们使用了 FLAG_UPDATE_CURRENT 标记,所以这里可以更新我们在上面创建的
// PendingIntent
val updatedPendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_REQUEST_CODE,
updatedIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
// 该 PendingIntent 已被更新
复制代码
在接下来的内容中我们会解释为什么将
PendingIntent
设置为可变类型。
跨应用 API
通常的用法并不局限于与系统交互。虽然在某些操作后使用 startActivityForResult() 和 onActivityResult() 来 接收回调 是非常常见的用法,但它并不是唯一用法。
想象一下一个线上订购应用提供了 API 使其他应用可以集成。当
Intent
启动了订购食物的流程后,应用可以
Intent
的
extra
的方式访问
PendingIntent
。一旦订单完成传递,订购应用仅需启动一次
PendingIntent
。
在本例中,订购应用使用了
PendingIntent
而没有直接发送 activity 结果,因为订单可能需要更长时间进行提交,而让用户在这个过程中等待是不合理的。