且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-10-29 19:36:16

Doze 模式会将您的警报延迟到下一个维护时段.为避免打盹模式阻止您的闹钟,您可以使用 setAndAllowWhileIdle(), setExactAndAllowWhileIdle()setAlarmClock().您将有大约 10 秒的时间来执行您的代码,并设置您的下一个闹钟(不过对于带有 _AndAllowWhileIdle 的方法,每 15 分钟不超过一次)

如果你想测试 Doze 模式,你可以使用 亚行命令:

  1. 使用 Android 6.0(API 级别 23)或更高版本的系统映像配置硬件设备或虚拟设备.

  2. 将设备连接到您的开发机器并安装您的应用.

  3. 运行您的应用并使其保持活动状态.
  4. 关闭设备屏幕.(该应用程序保持活动状态.)通过运行以下命令强制系统在打盹模式下循环:

    adb shell dumpsys 电池拔掉

    adb shell dumpsys deviceidle 步骤

  5. 您可能需要多次运行第二个命令.重复此操作,直到设备状态变为空闲.

  6. 在您重新激活设备后观察您的应用的行为.确保应用在设备退出 Doze 时正常恢复.

添加 setAlarmClock 示例

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

AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent = new Intent(this, MyAlarmReceiver.class);//或者只是 new Intent() 用于隐式意图//设置动作以知道这是来自闹钟intent.setAction("from.alarm.clock");PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);//5s内报警.am.setAlarmClock(new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + 5000, pi), pi);

I've made an app that always worked until Android 6.0. I think it's the Doze feature that it's not allowing my Alarm to fire.

I use sharedpreferences to handle the options:

//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);

Any clue of whats wrong here?

This is an app to block calls. Thank you!

EDIT: I have 3 files (more but...) like:

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

The Doze mode will delay your alarm until the next maintenance window. To avoid the Doze mode to block your alarm, you can use setAndAllowWhileIdle(), setExactAndAllowWhileIdle() or setAlarmClock(). You will have about 10s to execute your code, and set your next alarm (not more than once per 15min for methods with _AndAllowWhileIdle though)

If you want to test the Doze mode, you can use 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.

Edit: Add setAlarmClock example

Don't forget to check the SDK level (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);