如果强制关闭目标应用程序,PendingIntent 会发生什么情况?
What happens to a PendingIntent if the target app was force-closed?
我实际上正在开发一个应该 post 5 天后通知的应用程序。
我使用 AlarmManager 向我的接收器发送一个 PendingIntent class。
一切正常,直到我强行关闭我的应用程序。在这种情况下,通知不会出现。
所以我的问题是:
已触发但未达到目标的 PendingIntent 会怎样?
当我的应用程序最终重新启动时,我可以检查未达到目标的 PendingIntents 吗?
编辑 1:
这些是我的广播接收器的基本部分:
override fun onReceive(context: Context?, intent: Intent?) {
if (context != null && intent?.action != null) {
when (intent.action) {
INTENT_ACTION_BOOT_COMPLETED -> handleDeviceBoot()
INTENT_ACTION_REMINDER -> handleReminder(context, intent.getLongExtra(EXTRA_ITEM_ID, -1))
}
}
}
private suspend fun schedule(context: Context, itemId: Long, fireDate: LocalDateTime) = withContext(Dispatchers.IO) {
AlarmManagerCompat.setAndAllowWhileIdle(
getAlarmManager(context),
AlarmManager.RTC,
fireDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(),
makePendingIntent(context, itemId)
)
with(AppDatabase.get(context).reminderDao()) {
val oldReminder = getItemReminder(itemId)
if (oldReminder == null) {
insert(Reminder(itemId = itemId, fireDate = fireDate))
} else {
update(Reminder(id = oldReminder.id, itemId = itemId, fireDate = fireDate))
}
}
}
private suspend fun cancel(context: Context, itemId: Long) = withContext(Dispatchers.IO) {
val reminderDao = AppDatabase.get(context).reminderDao()
val reminder = reminderDao.getItemReminder(itemId)
reminder?.let {
getAlarmManager(context).cancel(makePendingIntent(context, itemId))
reminderDao.delete(it)
}
}
private fun getAlarmManager(context: Context) = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
private fun makePendingIntent(context: Context, itemId: Long): PendingIntent {
val alarmIntent = Intent(context, ReminderManager::class.java).apply {
action = INTENT_ACTION_REMINDER
putExtra(EXTRA_ITEM_ID, itemId)
}
return PendingIntent.getBroadcast(context, itemId.toInt(), alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
定义见Official Android Documentation
PendingIntent 本身只是对系统维护的令牌的引用,描述了用于检索它的原始数据。这意味着,即使它拥有的应用程序的进程被终止,PendingIntent 本身仍可从已获得它的其他进程使用。如果创建应用程序稍后重新检索相同类型的 PendingIntent(相同的操作、相同的 Intent 操作、数据、类别和组件以及相同的标志),它将收到表示相同标记的 PendingIntent(如果它仍然有效),并且可以因此调用 cancel() 将其删除。
重新访问您的代码以检查是否有任何其他原因会导致此问题。
当您 "force close" 一个应用程序时,该应用程序被设置为 "stopped state"。在 "stopped state" 中,您的应用程序不会被 Android 自动启动,直到用户手动重新启动应用程序。这意味着如果您 "force close" 您的应用程序,您的应用程序将不会收到任何广播 Intent
直到用户手动重新启动它。
我希望(虽然我自己没有尝试过),如果您安排闹钟在时间 X 和时间 X 之前关闭,您 "force close" 应用程序,当时间 X 发生时,闹钟管理器将尝试发送 PendingIntent
,但是 Android 将拒绝实际执行 BroadcastReceiver
,因为该应用程序位于 "stopped state" 中。在这种情况下,我预计触发器会丢失。 Android 不会重试或重新安排。
基本上,当用户 "force close" 使用应用程序时,他是在告诉 Android 他不希望该应用程序再 运行,包括该应用程序运行的任何后台进程将来可能有,或者想开始。
答案很简短:活动的 PendingIntents 在应用程序强制停止时被取消。
我实际上正在开发一个应该 post 5 天后通知的应用程序。
我使用 AlarmManager 向我的接收器发送一个 PendingIntent class。 一切正常,直到我强行关闭我的应用程序。在这种情况下,通知不会出现。
所以我的问题是: 已触发但未达到目标的 PendingIntent 会怎样? 当我的应用程序最终重新启动时,我可以检查未达到目标的 PendingIntents 吗?
编辑 1:
这些是我的广播接收器的基本部分:
override fun onReceive(context: Context?, intent: Intent?) {
if (context != null && intent?.action != null) {
when (intent.action) {
INTENT_ACTION_BOOT_COMPLETED -> handleDeviceBoot()
INTENT_ACTION_REMINDER -> handleReminder(context, intent.getLongExtra(EXTRA_ITEM_ID, -1))
}
}
}
private suspend fun schedule(context: Context, itemId: Long, fireDate: LocalDateTime) = withContext(Dispatchers.IO) {
AlarmManagerCompat.setAndAllowWhileIdle(
getAlarmManager(context),
AlarmManager.RTC,
fireDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(),
makePendingIntent(context, itemId)
)
with(AppDatabase.get(context).reminderDao()) {
val oldReminder = getItemReminder(itemId)
if (oldReminder == null) {
insert(Reminder(itemId = itemId, fireDate = fireDate))
} else {
update(Reminder(id = oldReminder.id, itemId = itemId, fireDate = fireDate))
}
}
}
private suspend fun cancel(context: Context, itemId: Long) = withContext(Dispatchers.IO) {
val reminderDao = AppDatabase.get(context).reminderDao()
val reminder = reminderDao.getItemReminder(itemId)
reminder?.let {
getAlarmManager(context).cancel(makePendingIntent(context, itemId))
reminderDao.delete(it)
}
}
private fun getAlarmManager(context: Context) = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
private fun makePendingIntent(context: Context, itemId: Long): PendingIntent {
val alarmIntent = Intent(context, ReminderManager::class.java).apply {
action = INTENT_ACTION_REMINDER
putExtra(EXTRA_ITEM_ID, itemId)
}
return PendingIntent.getBroadcast(context, itemId.toInt(), alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
定义见Official Android Documentation
PendingIntent 本身只是对系统维护的令牌的引用,描述了用于检索它的原始数据。这意味着,即使它拥有的应用程序的进程被终止,PendingIntent 本身仍可从已获得它的其他进程使用。如果创建应用程序稍后重新检索相同类型的 PendingIntent(相同的操作、相同的 Intent 操作、数据、类别和组件以及相同的标志),它将收到表示相同标记的 PendingIntent(如果它仍然有效),并且可以因此调用 cancel() 将其删除。
重新访问您的代码以检查是否有任何其他原因会导致此问题。
当您 "force close" 一个应用程序时,该应用程序被设置为 "stopped state"。在 "stopped state" 中,您的应用程序不会被 Android 自动启动,直到用户手动重新启动应用程序。这意味着如果您 "force close" 您的应用程序,您的应用程序将不会收到任何广播 Intent
直到用户手动重新启动它。
我希望(虽然我自己没有尝试过),如果您安排闹钟在时间 X 和时间 X 之前关闭,您 "force close" 应用程序,当时间 X 发生时,闹钟管理器将尝试发送 PendingIntent
,但是 Android 将拒绝实际执行 BroadcastReceiver
,因为该应用程序位于 "stopped state" 中。在这种情况下,我预计触发器会丢失。 Android 不会重试或重新安排。
基本上,当用户 "force close" 使用应用程序时,他是在告诉 Android 他不希望该应用程序再 运行,包括该应用程序运行的任何后台进程将来可能有,或者想开始。
答案很简短:活动的 PendingIntents 在应用程序强制停止时被取消。