I'm using Android's AlarmManager
to fire a notification on my app periodically based on a time set by the user on a settings screen. I've followed the documentation to implement that. It's done like the snippet below:
fun setDailyAlarm(time: Calendar, id: Int) {
val cal = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY))
set(Calendar.MINUTE, time.get(Calendar.MINUTE))
}
val pi = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
cal.timeInMillis,
AlarmManager.INTERVAL_DAY,
pi
)
}
I'm also using the Material Dialogs library to invoke a time dialog, as follows:
MaterialDialog(this).show {
// time here is a Calendar instance
timePicker { _, time ->
setDailyAlarm(time, ALARM_ID)
}
}
The screen looks like the example below:
The alarm itself is firing, but there's a weird bug happening.
Say that it's 9 PM and I set the alarm to 10 AM. I believe the expected behavior should be to fire the alarm the next day at 10 AM but once the clock reaches 10 PM sometimes I get a "false positive". (By sometimes I mean that this behavior is not even consistent. I managed to replicate it a few times, and my clients also complained about it).
Note: The app's minimum API level is 21.
At first, I thought the calendar object might've been getting the wrong AM/PM flag, or the Calendar.HOUR_OF_DAY
property might've been wrong, but when I checked those values in the debugger everything seemed to be fine. So now I'm clueless to what the problem might be.
Is there something that I'm missing here?
I've found a solution to this problem.
After doing some tests I noticed that the problem only happened when I set the time to something previous to the current hour. Then it occurred to me that perhaps the AlarmManager
might automatically fire "old alarms" so that might've been why I was getting that false positive.
Then I changed my setDailyAlarm()
function to the snippet below:
fun setDailyAlarm(time: Calendar, id: Int) {
val now = Calendar.getInstance()
val cal = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY))
set(Calendar.MINUTE, time.get(Calendar.MINUTE))
}
if (time.get(Calendar.HOUR_OF_DAY) <= now.get(Calendar.HOUR_OF_DAY)) {
cal.add(Calendar.DATE, 1)
}
val pi = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
cal.timeInMillis,
AlarmManager.INTERVAL_DAY,
pi
)
}
TL;DR: I'm checking whether or not the chosen time is before the current time, and if that's the case I add one day to the Calendar
instance before creating the PendingIntent
. It seems to have solved the issue since the alarm is not firing at the wrong time anymore.