Android 6.0 Doze 模式中的警报管理器问题

Alarm Manager issue in Android 6.0 Doze mode

我制作了一个在 Android 6.0 之前一直有效的应用程序。我认为是 Doze 功能不允许我的闹钟触发。

我使用 sharedpreferences 来处理选项:

//ENABLE NIGHT MODE TIMER
    int sHour = blockerTimerPreferences.getInt("sHour", 00);
    int sMinute = blockerTimerPreferences.getInt("sMinute", 00);

    Calendar sTime = Calendar.getInstance();
    sTime.set(Calendar.HOUR_OF_DAY, sHour);
    sTime.set(Calendar.MINUTE, sMinute);

    Intent enableTimer = new Intent(context, CallReceiver.class);
    enableTimer.putExtra("activate", true);
    PendingIntent startingTimer = PendingIntent.getBroadcast(context, 11002233, enableTimer, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager sAlarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    sAlarm.setRepeating(AlarmManager.RTC_WAKEUP,
            sTime.getTimeInMillis(),
            AlarmManager.INTERVAL_DAY, startingTimer);

这里有什么问题的线索吗?

这是一款拦截来电的应用。谢谢!

编辑: 我有 3 个文件(更多但...),例如:

MainActivity (All code)
CallReceiver (Broadcast that triggers the alarm again (reboot etc))
CallReceiverService (Handles the call / phone state)

如果设备处于打瞌睡模式,您需要使用其中之一 API: setExactAndAllowWhileIdlesetAndAllowWhileIdle.

请注意,没有 API 可以在重复闹钟的打瞌睡模式下唤醒设备,因此如果您需要重复闹钟来在打瞌睡时唤醒设备,您必须使用 APIs 并在每次触发定时器时重新启动定时器。

打瞌睡模式会将您的警报延迟到下一次维护 window。避免了Doze mode to block your alarm, you can use setAndAllowWhileIdle(), setExactAndAllowWhileIdle() or setAlarmClock()。您将有大约 10 秒的时间来执行您的代码,并设置您的下一个警报(但是对于 _AndAllowWhileIdle 的方法每 15 分钟不超过一次)

如果你想测试Doze模式,你可以使用ADB command:

  1. Configure a hardware device or virtual device with an Android 6.0 (API level 23) or higher system image.

  2. Connect the device to your development machine and install your app.

  3. Run your app and leave it active.
  4. Shut off the device screen. (The app remains active.) Force the system to cycle through Doze modes by running the following commands:

    adb shell dumpsys battery unplug

    adb shell dumpsys deviceidle step

  5. You may need to run the second command more than once. Repeat it until the device state changes to idle.

  6. Observe the behavior of your app after you reactivate the device. Make sure the app recovers gracefully when the device exits Doze.

编辑:添加 setAlarmClock 示例

不要忘记检查 SDK 级别 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)

AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, MyAlarmReceiver.class); //or just new Intent() for implicit intent 
//set action to know this come from the alarm clock
intent.setAction("from.alarm.clock");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//Alarm fire in 5s.
am.setAlarmClock(new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + 5000, pi), pi);