问题
I'm trying to develop a kind of reminders system, so user can enter days for reminders (MON, TUE...) and times on which this reminder will fire (only hour and minutes). It can be any day of the week or multiple days of the week. Here is the code for setting these reminders:
final AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
for (final Day day: reminder.getDays()) {
for (final ReminderTime reminderTime: reminder.getTimes()) {
final Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, reminderTime.getHour());
calendar.set(Calendar.MINUTE, reminderTime.getMinute());
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.DAY_OF_WEEK, day.getCalendarDay());
if (calendar.getTimeInMillis() < System.currentTimeMillis()) {
// final long daysDifference = DateUtils.getDaysDifference(calendar.getTimeInMillis(), System.currentTimeMillis());
// calendar.add(Calendar.DAY_OF_YEAR, (int) (daysDifference + 1));
calendar.add(Calendar.DAY_OF_YEAR, 7);
}
final Intent intent = createReminderIntent(context, reminder.getReminderType(), reminderTime, day);
final PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, sender);
}
}
The alarm I recieve later in custom BroadcastReceiver
.
The problem is that the reminder is firing from time to time and sometimes not, seems to me that something is woring with the days. I'm wondering were is the bug or what I'm doing wrong?
回答1:
When calling PendingIntent.get*(...)
with the same Intent
and request code the same instance of PendingIntent
is returned.
The AlarmManager
can have only one rule associated for one PendingIntent
which means that only the last alarm set by AlarmManager.setRepeating(...)
in your code is actually active. The others got overwritten by this last rule.
One way to differentiate PendingIntent
s with the same Intent
is to use a different request code for each. When passed to AlarmManager
these will trigger individual alarms as expected.
Sadly there's no way to cancel multiple alarms defined e.g. by base Intent
so you have to either
- keep all your
PendingIntent
instances used originally to schedule the alarms - keep all the request codes and reconstruct said
PendingIntent
s - or use similar mechanism.
Then you need to call AlarmManager.cancel(pi)
with each of these PendingIntent
s individually to cancel associated alarms.
回答2:
Calendar Calendar_Object = Calendar.getInstance();
Calendar_Object.set(Calendar.DAY_OF_WEEK, 6);
Calendar_Object.setTimeInMillis(System.currentTimeMillis());
Calendar_Object.set(Calendar.HOUR_OF_DAY, 16);
Calendar_Object.set(Calendar.MINUTE, 51);
Calendar_Object.set(Calendar.SECOND, 0);
// MyView is my current Activity, and AlarmReceiver is the
// BoradCastReceiver
Intent myIntent = new Intent(MyView.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MyView.this,
0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
/*
* The following sets the Alarm in the specific time by getting the long
* value of the alarm date time which is in calendar object by calling
* the getTimeInMillis(). Since Alarm supports only long value , we're
* using this method.
*/
Long alarmTime = Calendar_Object.getTimeInMillis();
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime, 7 * 24 * 60 * 60 * 1000 , pendingIntent);
来源:https://stackoverflow.com/questions/30333747/alarm-manager-repeating-alarm-not-always-fires