无法在6.0及以上版本上准确设置计划时间

时间:2017-03-15 12:42:54

标签: android alarmmanager android-6.0-marshmallow android-alarms

我试图制作一个应用程序,要求计划时间准确无误。我需要在特定时间重置app内生成的日志(驱动程序职责信息)。

我尝试使用setAlarm,但它在6.0及以上版本上无法正常使用。因为它应该在没有互联网的情况下工作,我无法使用Push Notification.我也尝试使用setAlarmClock,但它也不能正常工作。

我需要alarm准确1小时24小时

更新

日志警报

public static void startLogAlarm(Context ctx,long milliseconds) {

    final int SDK_INT = Build.VERSION.SDK_INT;

    // 1 Day = 86400 seconds = 86400000 milliseconds
    long timeInMillis = System.currentTimeMillis() + milliseconds;

    AlarmManager alarmManager = (AlarmManager) ctx
            .getSystemService(Context.ALARM_SERVICE);

    Intent intent = new Intent(ctx, eLogReceiver.class);
    intent.setAction(Utility.eLOG_ACTION);
    PendingIntent pi = PendingIntent.getBroadcast(ctx, 3, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    if (SDK_INT < Build.VERSION_CODES.KITKAT) {

       alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, pi);

    } else if (Build.VERSION_CODES.KITKAT <= SDK_INT && SDK_INT < Build.VERSION_CODES.M) {

       alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, pi);

    } else if (SDK_INT >= Build.VERSION_CODES.M) {

    //  AlarmManager.AlarmClockInfo alarmClockInfo = new  AlarmManager.AlarmClockInfo(timeInMillis, pi);
    //  alarmManager.setAlarmClock(alarmClockInfo, pi);

        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, pi);

    }
}

// Start Alarm
Utility.startLogAlarm(this, Constants.DAY_MILLISECONDS);

public class Constants {

   public static final long HOUR_MILLISECONDS = 3600000;
   public static final long DAY_MILLISECONDS = 86400000;
}

传感器警报

 public static void startSensorAlarm(Context ctx, long timeInMillis) {

    final int SDK_INT = Build.VERSION.SDK_INT;

    AlarmManager alarmManager = (AlarmManager) ctx
            .getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(ctx, AlarmReceiver.class);
    intent.setAction(Utility.SENSOR_ACTION);
    PendingIntent pi = PendingIntent.getBroadcast(ctx, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    if (SDK_INT < Build.VERSION_CODES.KITKAT) {
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeInMillis, pi);
    } else if (Build.VERSION_CODES.KITKAT <= SDK_INT && SDK_INT < Build.VERSION_CODES.M) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeInMillis, pi);
    } else if (SDK_INT >= Build.VERSION_CODES.M) {

        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeInMillis, pi);

     //AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(System.currentTimeMillis()+timeInMillis, pi);
        alarmManager.setAlarmClock(alarmClockInfo, pi);
    }

    showLog("Sensor Alarm Time", timeInMillis + "");
}

群组闹钟

 public static void startGroupAlarm(Context ctx) {

    final int SDK_INT = Build.VERSION.SDK_INT;

    AlarmManager alarmManager = (AlarmManager) ctx
            .getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(ctx, AlarmReceiver.class);
    intent.setAction(Utility.GROUP_UPDATE_ACTION);
    PendingIntent pi = PendingIntent.getBroadcast(ctx, 2, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    if (SDK_INT < Build.VERSION_CODES.KITKAT) {
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + INTERVAL_EVERY_8_HOURS, pi);
    } else if (Build.VERSION_CODES.KITKAT <= SDK_INT && SDK_INT < Build.VERSION_CODES.M) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + INTERVAL_EVERY_8_HOURS, pi);
    } else if (SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + INTERVAL_EVERY_8_HOURS, pi);
    }

    Utility.showLog("Group Alarm", "Started");

}

LogNoticeAlarm

 public static void startLogNoticeAlarm(Context ctx, long milliseconds) {

    final int SDK_INT = Build.VERSION.SDK_INT;

    // 1 Hour = 3600 seconds = 3600000 milliseconds
    long HourMilliseconds = System.currentTimeMillis() + milliseconds;

    AlarmManager alarmManager = (AlarmManager) ctx
            .getSystemService(Context.ALARM_SERVICE);

    Intent intent = new Intent(ctx, eLogNoticeReceiver.class);
    intent.setAction(Utility.eLOG_NOTICE_ACTION);
    PendingIntent pi = PendingIntent.getBroadcast(ctx, 4, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    if (SDK_INT < Build.VERSION_CODES.KITKAT) {
        alarmManager.set(AlarmManager.RTC_WAKEUP, HourMilliseconds, pi);
    } else if (Build.VERSION_CODES.KITKAT <= SDK_INT && SDK_INT < Build.VERSION_CODES.M) {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, HourMilliseconds, pi);
    } else if (SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + milliseconds, pi);

     // AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(HourMilliseconds, pi); // alarmManager.setAlarmClock(alarmClockInfo, pi);

    }

}

我一直在使用总共4个警报1个需要每5分钟安排一次,休息时间为1小时8小时24小时。那传感器警报(每5分钟一次)是否导致其他警报出现问题?

请建议最佳解决方案

注意:关于SO的所有其他问题都无效。

2 个答案:

答案 0 :(得分:0)

显然这个因为每隔5分钟发出警报就会引起问题。所以其他警报会因为两次警报同时发生而导致失败。

所以我的建议是将你的其他闹钟时间设置为1或2分钟之后/之前(即8小时2分钟而不是8小时)。

注意: 1或2分钟应完全取决于您的铃声持续时间。

答案 1 :(得分:0)

有几种方法可以解决这个问题。

首先要注意Android Alarm Documentation

中的这个(释义)引用
  

警报管理器旨在在特定时间运行您的代码,即使您的应用当前未运行。对于正常的计时操作(刻度等),使用处理程序更容易,也更有效。

您可以详细了解权衡here。话虽如此,我会在保持所有警报的基础上回答。同一文献中的另一个引用提到:

  

从API 19(KITKAT)开始,警报传递不准确:操作系统将移动警报以最小化唤醒... targetSdkVersion早于API 19的应用程序将继续看到先前的行为。

这实际上是指Doze Mode,其中指出:

  

AlarmManager警报(包括setExact())被推迟到下一个维护窗口。

从同一documentation on dozing

中窃取Google的图片

doze vizualization

这对您来说意味着,如果您有相互靠近的警报,设备将在下一个维护周期中批量处理它们,但如果您设置了 targetSdkVersion更低,您可以轻松修复以排除批处理行为(,但代价是其他已编译的改进)。

假设您实际上坚持使用Doze行为,切换到扩展常规BroadCastReceiver的{​​{3}}内容有助于确保您有时间回复RTC_WAKEUP警报。

您还可以使用多个BroadcastReceiver,以便Android单独处理它们(而不是将它们分配到每分钟一次/维护)。这只意味着在不同的接收器上处理不同的待处理意图:

Intent intent = new Intent(ctx, AlarmReceiver.class);
...
Intent intent = new Intent(ctx, AlarmReceiver2.class); //a different receiver class
...

我的代码中不清楚eLogNotice接收器是否是其他警报使用的同一接收器的实例。