This example is suited for repeating alarm at certain interval (e.g. hourly, daily, etc) but doesn't gurantee accuracy of repeating time (e.g. 9am daily). Refer to Caveats of Repeating Alarm.
class ReminderReceiver : BroadcastReceiver() { companion object { private const val REQUEST_TIMER1 = 1 fun getIntent(context: Context, requestCode: Int): PendingIntent? { val intent = Intent(context, ReminderReceiver::class.java) // https://developer.android.com/reference/android/app/PendingIntent.html#getBroadcast(android.content.Context,%20int,%20android.content.Intent,%20int) return PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT) } fun startAlarm(context: Context) { val pendingIntent = getIntent(context, REQUEST_TIMER1) val alarm = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager /* // trigger at 8:30am val alarmTime = LocalTime.of(8, 30) var now = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES) if (now.toLocalTime().isAfter(alarmTime)) { now = now.plusDays(1) } now = now.withHour(alarmTime.hour).withMinute(alarmTime.minute) // .withSecond(alarmTime.second).withNano(alarmTime.nano) val utc= now.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime() val triggerAtMillis = utc.atZone(ZoneOffset.UTC)!!.toInstant()!!.toEpochMilli() // first trigger at next 8:30am, then repeat each day alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, AlarmManager.INTERVAL_DAY, pendingIntent) */ // this alarm might execute between now to next day, and repeat daily alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), AlarmManager.INTERVAL_DAY, pendingIntent) } fun cancelAlarm(context: Context) { val pendingIntent = getIntent(context, REQUEST_TIMER1) val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmManager.cancel(pendingIntent) } } override fun onReceive(context: Context, intent: Intent) { Timber.d("onReceive") Toast.makeText(context, "Alarm!", Toast.LENGTH_LONG).show() }}
Usage
ReminderReceiver.startAlarm(context)
NOTES:
PendingIntent.FLAG_CANCEL_CURRENT
to make sure only 1 alarm is created/overwritten no matter how many timesstartAlarm
is called- setInexactRepeating: The alarm's first trigger will not be before the requested time, but it might not occur for almost a full interval after that time. In addition, while the overall period of the repeating alarm will be as requested, the time between any two successive firings of the alarm may vary.
triggerAtMillis
indicate when is the first time it should triggered. If the time has passed, it might trigger immediately.triggerAtMillis
is in GMT/UTC
Caveats of Repeating Alarm
If an alarm is delayed (by system sleep, for example, for non
_WAKEUP
alarm types), a skipped repeat will be delivered as soon as possible. After that, future alarms will be delivered according to the original schedule; they do not drift over time. For example, if you have set a recurring alarm for the top of every hour but the phone was asleep from 7:45 until 8:45, an alarm will be sent as soon as the phone awakens, then the next alarm will be sent at 9:00.
As of API 19, all repeating alarms are inexact. Because this method has been available since API 3, your application can safely call it and be assured that it will get similar behavior on both current and older versions of Android.
Your alarm's first trigger will not be before the requested time, but it might not occur for almost a full interval after that time. In addition, while the overall period of the repeating alarm will be as requested, the time between any two successive firings of the alarm may vary. If your application demands very low jitter, use one-shot alarms with an appropriate window instead; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent).
It seems as of API 19 (Android 4.4 - KitKat)
, calling setRepeating
is same as setInexactRepeating
. It is suitable for job that repeats within a certain interval (hourly, daily, etc.), but doesn't need to execute at the exact time (e.g. 9am every day). I believe the repeating alarm will drift (as setRepeating
behaviour is inexact as of API 19), as in the following sequence might occur
- Day 1: 9am
- Day 2: 9.05am
- Day 3: 9.30am
- Day 4: 10am
- Day 5: 10am
- Day 6: 11.30am
If you need to repeat at specific time daily (e.g. 9am every day), use setExact or setWindow (allow slight delay as per the window specified, but more energy efficient). If you need extreme accuracy (e.g. Alarm Clock) and execute even though the system is in low-power idle modes, use setExactAndAllowWhileIdle.
You have to program the repetition part yourself, set the next alarm again after the current alarm is triggered at onReceive
.
Refer to Daily Repeating Alarm/Reminder at Specific Time With AlarmManager.
Set Alarm Timing Example
Example: trigger once immediately.
val triggerAtMillis = System.currentTimeMillis()alarm.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent)
Example: trigger once 5 minutes later.
val intervalMillis = 5L * 60L * 1_000Lval triggerAtMillis = System.currentTimeMillis() + intervalMillisalarm.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent)
Example: trigger once every 5 minutes
val intervalMillis = 5L * 60L * 1_000Lval triggerAtMillis = System.currentTimeMillis() + intervalMillisalarm.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, intervalMillis, pendingIntent)
AndroidManifest.xml
Edit AndroidManifest.xml
.
```xml
<manifest ..>
<application ...>
<receiver android:name=".ReminderReceiver" />
</application>
</manifest>
NOTE: The AlarmManager
won't survive a device reboot. You have to implement a device bootup receiver and call ReminderReceiver.startAlarm(context)
.
NOTE: Refer Setup Android Notification.
NOTE: To support multiple alarm, use a different requestCode
for each alarm. Refer Android AlarmManager: Multiple Alarm With Arguments/Parameters.
NOTE: AlarmManager is removed when the app is uninstalled, and it seems the Alarm is cancelled after APK update (not sure if this is true or always true).
References: