TLDR:如果计划的alarmClockInfo(PendingIntent)打开一个服务实例,而应用程序位于前面,并且通过
context.bindService()
有一个活动服务实例...
并且警报不会触发通知...
出现 Context.startForegroundService() did not then call Service.startForeground()
错误。
详情:
我的目标是当应用程序位于前端时,通知以静默方式排队...这意味着当正在处理一个通知时(打开活动的操作),传入的预定警报会填充服务实例内的队列...并且不显示任何抬头通知。
我的问题是...与这里的大多数情况相反,我无法控制服务启动的方式,在本例中是通过 AlarmManager 调度。
@RequiresApi(api = Build.VERSION_CODES.O)
public static PendingIntent foregroundServicePendingIntent(Context context, int reqCode, Supplier<Intent> intentSupplier) {
assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
return PendingIntent.getForegroundService(myService,
reqCode,
intentSupplier.get(),
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
}
意图是基本的东西......使用上下文+目标构造函数(
android.content.Intent#Intent(android.content.Context, java.lang.Class<?>)
),以及包含信息的包。以 MyService.class 作为目的地。
请注意,PednignIntent 正在安排一个从 MyService 到同一个 MyService 的预定警报。
(我已经看到了广播中介选项,但我还不明白如果广播者仍然被迫进入服务顺序事件循环,为什么需要这种间接)
日程安排如下:
assert isAtLeastOreo;
PendingIntent pendingIntent =
PendingIntent.getActivity( // This defines what will get shown when clicking in the clock icon on top of the android status bar.
context,
prefix_code + id,
openAlarmsFragmentIntent,
flag);
manager.setAlarmClock(
new AlarmManager.AlarmClockInfo(timeMillis, pendingIntent),
foregroundServicePendingIntent // variable created via foregroundServicePendingIntent(context, intent)
);
由于不再允许“VERSION O (26+)” Trampoline 事件,这意味着无论 Service 在解析 Trampoline Action 之前执行什么逻辑,现在都需要在创建/到达 Activity 目标后在目标中进行解析,因此,活动目标中的服务实例必须在
onCreate()
或 onNewIntent(Intent)
中解析 Intent 的捆绑包。
这可能是导致错误的原因...
当服务处理平视通知时...虽然应用程序尚未出现在前面,但什么也没有发生,一切都很好。 多个通知可以处理同一个 Service 实例并且不会出现错误......很好。
** 案例A:
如果我安排一个闹钟...不会出现错误:
当单个通知的
Action
打开“MainActivity”时...
根据通知的要求,此 Activity 必须实现 Intent 的捆绑解析,必须获取 Service 实例...
我有一个单例,当警报第一次调用服务时,它会被分配,当服务调用
onDestroy()
时,它会被清除。
一旦Activity打开,我就可以使用Service来执行更多的闹钟调度任务。搬迁、推迟...等等...
没有出现错误。
现在,如果第二个通知在事件发生后到达,则错误出现,无论此警报是在 Activity 被置于前面之后立即出现、5 秒还是 1 分钟后出现。
** 情况 B:
如果 MainActivity 首先实例化服务,也会发生这种情况...通过:
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
在这种情况下,服务变得活跃...绑定了 MainActivity 生命周期,该服务还存储在一个被清除的单例中
onDestroy()
。
没有错误,当:
后台有 Activity 和 Service...
单个计划警报打开服务实例(MainActivity 中的同一实例),构建并显示通知。
Notification Action 打开Activity实例触发
onNewIntent(Intent)
Activity 使用 Service 实例继续 Intent 操作+额外的东西...
...完成...没问题。
错误发生时间:
在步骤“3”之后,如果第二个警报响起
onStartCommand(Intent intent, int flags, int startId)
,则应用程序将在 5 秒后出现 ANR 错误。
我无法控制警报如何决定打开服务,因为这是在创建 AlarmClockInfo 时指定的,所以我不知道应该如何解决这个问题...
一个关键事实是...一旦选择了通知中的操作(打开活动),随后由计划的 PendingIntents 触发的每个
onStartCommand(Intent intent, int flags, int startId)
将不会构建并显示任何新的平视通知。
当我让通知出现时,错误消失了。
这意味着...当服务通过由计划的 AlarmClockInfo 触发的 PendingIntent 打开时...甚至可能来自其他来源...
服务有义务让通知出现...
这很奇怪,因为它与服务根据文档应该服务的目的不一致,这不一定是显示通知,但它也可能用于执行其他后台任务......
另一个罪魁祸首可能是 AlarmScheduler 触发服务激活的方式,这表明它的唯一功能应该是显示通知。
总而言之,这似乎是一种安全对策……老实说,这对我来说似乎没问题。