我需要每10分钟计划一次任务。

由于在Lollipop和更高版本中,setRepeating()不精确,因此我使用setExact(),并且(在触发警报时)我在10分钟内设置了新的确切警报。

private void setAlarm(long triggerTime, PendingIntent pendingIntent) {
        int ALARM_TYPE = AlarmManager.ELAPSED_REALTIME_WAKEUP;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            alarmManager.setExact(ALARM_TYPE, triggerTime, pendingIntent);
        } else {
            alarmManager.set(ALARM_TYPE, triggerTime, pendingIntent);
        }
    }
triggerTime是计算得出的SystemClock.elapsedRealtime() + 600_000;
警报响起时,首先我要计划一个新警报,然后再执行我的任务。
setAlarm();
mySheduledTask;

我的 list 中确实有WAKE_LOCK权限。

当我在Android 4上进行测试时,它可以完美运行(偏差可能是12-15 毫秒)。

但是当我在小米Redmi Note 3 Pro(5.1.1)上运行应用程序时-偏差可能高达 15秒!

例如,我在日志文件中看到:第一次运行是在1467119934477(RTC时间),第二次是1467120541683。区别是 607_206 毫秒,而不是 600_000 ,这是按计划的!

我想念什么? 有什么方法可以模拟系统警报的行为(这是可以描述我的策略的最接近的用例)?

PS。 我将IntentService用于PendingIntent = PendingIntent.getService(context, 0, myIntent, 0);

最佳答案

操作系统会根据您指定的时间来选择警报的工作方式。因此,当手机进入“半 sleep ”模式时,无需在您希望的时候使用该资源。基本上,它将等待操作系统为其打开的“窗口”,然后只有您要运行的警报才会运行,这就是您遇到时间间隔的原因。

这是在Marshmallow OS上引入的,并将在Nougat OS上继续使用,作为Google努力改善设备电池电量的一部分。

事情在这里,您有2个选择:

  • 接受时间延迟(但可以考虑使用 JobScheduler ,这是更推荐的选择,它将节省您的电池电量)。
  • 使用 setExactAndAllowWhileIdle 可能会导致电池问题(请谨慎使用,否则警报过多会对电池造成不良影响)。
    该方法不再重复,因此您必须声明下一个要在未完成的Intent打开的服务上运行的作业。

  • 如果选择选项2,则从这里开始:
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    int ALARM_TYPE = AlarmManager.RTC_WAKEUP;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        am.setExactAndAllowWhileIdle(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
        am.setExact(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
    else
        am.set(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
    

    10-04 19:56