我知道在这个主题上有很多关于SO的类似线程,但我找不到真正解决问题/或确定根本原因的线程。
首先,我正在瞄准SDK 22(Android 5.1),这意味着我可以使用AlarmManager + WakefulBroadcastReceiver + IntentService,即使这不是最新的做事方式。 我对JobScheduler等解决方案不感兴趣,我只是想了解发生了什么以及为什么。
我正在测试的手机有Android 8.0,但是因为我的目标是Android 5.1,所以无关紧要。
所以我正在处理的代码会为第二天06:00设置闹钟。
private fun setupAlarm() {
val calendar = Calendar.getInstance()
calendar.timeInMillis = System.currentTimeMillis()
calendar.add(Calendar.DAY_OF_YEAR, 1)
calendar.set(Calendar.HOUR_OF_DAY, 6)
calendar.set(Calendar.MINUTE, 0)
val alarmIntent = Intent(this, AlarmReceiver::class.java)
val alarmPendingIntent = PendingIntent.getBroadcast(this, 1221, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, alarmPendingIntent)
}
AlarmReciever仅启动服务:
class AlarmReceiver : WakefulBroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
startWakefulService(context, Intent(context, DownloadingIntentService::class.java));
}
}
此服务然后尝试下载文件,完成后调用completeWakefulIntent(intent)方法,让系统知道它完成了它的工作。
我无法弄清楚它什么时候起作用,什么时候不起作用。一天早上,它做了它应该拥有的东西,另一方面它没有。
我设置了一个远程LogCat功能,以查看IntentService是否已启动但到目前为止我看不到它的任何日志,因此这意味着不会触发警报。
如果我在下一分钟设置闹钟,甚至重复一个它应该的工作。但是,当我把明天早上的时间缩短时,那是非常不可靠的。
感谢您的帮助。
答案 0 :(得分:1)
我自己也遇到了这个问题。看看setRepeating方法会发生什么,让android系统调整警报被触发的时间。它很可能会尝试批量不同的警报,以优化电池使用。但在常规情况下,如果手机没有打瞌睡......它通常会在正确的时间发出警报。
但是,如果手机闲置一段时间,手机会进入打盹模式,因此报警会延迟。我个人观察到最多1个半小时的延误。
如果您希望它完全触发,您必须使用setExactAndAllowWhileIdle方法或setAlarmClock方法。在这种情况下,您必须自己处理下一个警报的日程安排。这些方法适用于打盹模式,并在准确的时间点击警报。
这些方法也有缺点。 setExactAndAllowWhileIdle方法只能用于每九分钟左右调度一次最大警报。 setAlarmClock方法主要向用户显示类似常规警报的通知,并将指示警报的详细信息(此行为因os版本的不同而异)
答案 1 :(得分:0)
我使用此代码每天触发备份。它对我有用,试一试。
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyReceiver.class);
intent.setAction("CUSTOM_INTENT");
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 06);
calendar.set(Calendar.MINUTE, 00);
// setRepeating() lets you specify a precise custom interval--in this case,
// 1 day
alarmMgr.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis()/1000,
AlarmManager.INTERVAL_DAY, alarmIntent);
答案 2 :(得分:0)
试试这个:
Calendar now = Calendar.getInstance();
Calendar alarm = Calendar.getInstance();
alarm.set(Calendar.HOUR_OF_DAY, hourOfDay);
alarm.set(Calendar.MINUTE, minute);
long alarmMillis = alarm.getTimeInMillis();
if (alarm.before(now)) alarmMillis+= 86400000L; //It will add 1 day if your time selected before now
//set alarm method of yours\\
settingAlarmManager(requestCode,alarmMillis);
private void settingAlarmManager(String requestCode, Calendar calendar) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(AddTaskActivity.this, AlarmReceiver.class);
PendingIntent broadcast = PendingIntent.getBroadcast(AddTaskActivity.this,
Integer.valueOf(requestCode), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, broadcast);
}
我的接收者课程:
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//do your stuff here\\
}
}
清单:
<receiver android:name=".utils.AlarmReceiver" />
我已尝试上面的代码来设置闹钟并执行我的自定义任务。也许这会对你有帮助。
答案 3 :(得分:0)
一些事情:
Alarm
的时间越早,the less precise it will be。 WakefulBroadcastReceiver
您正在尝试在Android 8.0中运行background job。值得探索Foreground Service:
您可能已经杀死了您的申请。当用户手动杀死某个应用时,在大多数设备中,所有Alarm
和PendingIntent
也会被杀死。
许多开发人员使用的调度策略不是设置重复Alarm
,而是有两个单独的Alarms连续重新安排(@Kushan在他的回答中提到了类似的内容)。
简而言之:
在一天中尽快启动Scheduler
(即使用户打开您的应用,也可以多次触发)。检查是否已存在所需的PendingIntents
(您的后台作业)。如果他们不这样做,只需安排他们。同样,在11.55左右安排另一个Alarm
。
所有这些午夜调度程序必须在5分钟内重新安排主AlarmManager
,然后安排作业和午夜警报< / em>接下来几天。
此方法允许您:
此外,尝试从您正在使用的API版本中获取最多:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
rtcStartingTime.getTimeInMillis(),
pendingIntent
);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
this.alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
rtcStartingTime.getTimeInMillis(),
pendingIntent
);
} else {
this.alarmManager.set(
AlarmManager.RTC_WAKEUP,
rtcStartingTime.getTimeInMillis(),
pendingIntent
);
}