setAlarmClock() 在打瞌睡模式下触发得太晚

setAlarmClock() fires too late in doze mode

我很难让我的收音机闹钟按预期工作,我在这里阅读了很多关于该主题的帖子,但不幸的是 none 确实帮助了我。

AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);        
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent penInt = PendingIntent.getBroadcast(this, intentId, intent, 0);

我在 Whosebug 上找到的这种区分 API 级别的方法并将其放入我的 calcNextAlarm() 函数(加上一些用于调试的日志消息)以正确设置警报,无论如何 API 正在设备上使用:

// problems in doze mode api 23+
if (Build.VERSION.SDK_INT >= 23) {
    if (testMode) Log.d("Ben", "setAlarmClock() - API 23+");
    am.setAlarmClock(new AlarmManager.AlarmClockInfo(alarmTimeInMillis, penInt), penInt);
}

else if (Build.VERSION.SDK_INT >= 19) {
// Wakes up the device in Idle Mode
    if (testMode) Log.d("Ben", "setExact() - API >= 19 && API < 23");
    am.setExact(AlarmManager.RTC_WAKEUP, alarmTimeInMillis, penInt);
}
// Old APIs
else {
    if (testMode) Log.d("Ben", "set() - API < 19");
    am.set(AlarmManager.RTC_WAKEUP, alarmTimeInMillis, penInt);
}

根据 Log.d 消息,我可以看到,在我的 Android 7.1 设备上,第一个方法 setAlarmClock() 正在执行以在接收器中设置警报。

经过 3 周的不成功测试和编码后,我真的很绝望 - 今天我的闹钟再次晚了 4 分钟 - 根据打瞌睡模式培训页面,这永远不应该发生:

Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.

在我的 7.1 phone 上,当我将闹钟设置为 "now +5 or 6" 分钟时,闹钟甚至会延迟 20 秒到 1:40 分钟。谁能告诉我如何真正及时完美地关闭闹钟?

尝试使用:

setExactAndAllowWhileIdle()

这将确保警报按时触发。我已经在我自己的应用程序中测试过它并且它是可靠的。

如果您的目标 API 小于 23,请将其保留在 if 子句中,该子句检查设备中当前安装的 api。仅在 API 级别 23 以上使用此功能,休息时继续使用 setExact

好的回答您的评论:

1) 我已经在没有插入电池的情况下在打瞌睡模式下准确地测试了它

2) 是的,不幸的是,对于空闲类型的警报,每 9 分钟限制一次警报。这里有两个选择:

首先使用 setExactAndAllowWhileIdle 触发第一个警报。

a) 对于贪睡,您必须使用 setAlarmClock 方法

b) 对于贪睡,您可以安排一个 JobScheduler 作业,将最小延迟时间设置为您的贪睡时间。这将确保作业至少在贪睡间隔的间隙得到安排。但这会导致作业在间隔后随机安排,因此您还需要将覆盖截止日期设置为 0,以便在最小延迟后立即安排作业。还要将网络要求保持为 none 并将需要的空闲模式保持为默认值或 false。根据我的经验,这也与警报精确方法一样可靠,我个人使用这种方法。

documentation 指出:

  • If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().

  • Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.

在 "Adapt your app to Doze" 部分还说:

Note: Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 minutes, per app.

setExactAndAllowWhileIdle 的文档说:

Unlike other alarms, the system is free to reschedule this type of alarm to happen out of order with any other alarms, even those from the same app. This will clearly happen when the device is idle (since this alarm can go off while idle, when any other alarms from the app will be held until later), but may also happen even when not idle. Note that the OS will allow itself more flexibility for scheduling these alarms than regular exact alarms, since the application has opted into this behavior. When the device is idle it may take even more liberties with scheduling in order to optimize for battery life.

所以 setExactAndAllowWhileIdle 不能保证准确执行,而 setAlarmClock 更准确(根据文档)。