6.0及以上无法准确设置日程时间
Unable to set schedule time accurately on 6.0 and above
我正在尝试制作一个需要准确安排时间的应用程序。我需要在特定时间重置应用程序内生成的日志(驾驶员职责信息)。
我尝试使用 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 上的所有其他问题均无效。
显然这个问题是由于每 5 个警报都会引起问题 min.So 其他警报会导致失败,因为两个警报同时触发。
所以我的建议是将您的其他闹钟时间设置为 1 或 2 分钟later/before(即 8 小时 2 分钟而不是 8 小时)。
注意:1 或 2 分钟应该完全取决于您的铃声持续时间。
有几种方法可以解决这个问题。
首先注意Android Alarm Documentation中的这个(转述的)引用:
Alarm Manager is intended to run your code at a specific time, even if your app is not currently running. For normal timing operations (ticks, etc) it is easier and much more efficient to use a Handler.
您可以阅读有关权衡的更多信息here。话虽这么说,我会在保持所有警报的基础上回答。同一文档中的另一引述提到:
Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups ... Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior.
这实际上指的是Doze Mode,其中指出:
AlarmManager alarms (including setExact()) are deferred to the next maintenance window.
盗用 Google 的图像 documentation on dozing:
这对你来说意味着,如果你有彼此接近的警报,设备将在下一个维护周期中对它们进行批处理,但如果你设置
targetSdkVersion
更低,您可以轻松修复排除批处理行为(但以其他编译改进为代价)。
假设您确实坚持打瞌睡行为,切换到扩展 WakefulBroadcastReceiver 而不是常规 BroadCastReceiver
可以帮助确保您有时间响应 RTC_WAKEUP
警报。
您还可以使用多个 BroadcastReceiver,以便 Android 分别处理它们(而不是将它们分批为每分钟一个/维护)。这只是意味着不同的未决意图在不同的接收者上得到处理:
Intent intent = new Intent(ctx, AlarmReceiver.class);
...
Intent intent = new Intent(ctx, AlarmReceiver2.class); //a different receiver class
...
从你的代码中我不清楚 eLogNotice 接收器是否是其他警报正在使用的同一接收器的实例。
我正在尝试制作一个需要准确安排时间的应用程序。我需要在特定时间重置应用程序内生成的日志(驾驶员职责信息)。
我尝试使用 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 上的所有其他问题均无效。
显然这个问题是由于每 5 个警报都会引起问题 min.So 其他警报会导致失败,因为两个警报同时触发。
所以我的建议是将您的其他闹钟时间设置为 1 或 2 分钟later/before(即 8 小时 2 分钟而不是 8 小时)。
注意:1 或 2 分钟应该完全取决于您的铃声持续时间。
有几种方法可以解决这个问题。
首先注意Android Alarm Documentation中的这个(转述的)引用:
Alarm Manager is intended to run your code at a specific time, even if your app is not currently running. For normal timing operations (ticks, etc) it is easier and much more efficient to use a Handler.
您可以阅读有关权衡的更多信息here。话虽这么说,我会在保持所有警报的基础上回答。同一文档中的另一引述提到:
Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups ... Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior.
这实际上指的是Doze Mode,其中指出:
AlarmManager alarms (including setExact()) are deferred to the next maintenance window.
盗用 Google 的图像 documentation on dozing:
这对你来说意味着,如果你有彼此接近的警报,设备将在下一个维护周期中对它们进行批处理,但如果你设置
targetSdkVersion
更低,您可以轻松修复排除批处理行为(但以其他编译改进为代价)。
假设您确实坚持打瞌睡行为,切换到扩展 WakefulBroadcastReceiver 而不是常规 BroadCastReceiver
可以帮助确保您有时间响应 RTC_WAKEUP
警报。
您还可以使用多个 BroadcastReceiver,以便 Android 分别处理它们(而不是将它们分批为每分钟一个/维护)。这只是意味着不同的未决意图在不同的接收者上得到处理:
Intent intent = new Intent(ctx, AlarmReceiver.class);
...
Intent intent = new Intent(ctx, AlarmReceiver2.class); //a different receiver class
...
从你的代码中我不清楚 eLogNotice 接收器是否是其他警报正在使用的同一接收器的实例。