Alarms

Alarms are used to start one of your app's component after a specified delay or at a exact time even outside the lifetime of your application. They are implemented with the AlarmManager class. 

With AlarmManager you can schedule your application's component to be run at some point in the future. You need to register your app with a PendingIntent, a wrapper for an Intent object whose component name specify the component to start when the alarm goes off. With the PendingIntent, AlarmManager can automatically send a broadcast, start an activity or a service of your app when the alarm goes off, i.e., AlarmManager can perform the action you described on your behalf at a later time.

Types of Alarms

They can be:
  • One-time: goes off at a specified time and only.
  • Repeating: goes off at a specified time and then after each pass of the specified interval.
If the trigger time you specify is in the past, the alarm triggers immediately.

And:
  • Elapsed real time: uses the "time since system boot" as a reference. It is suited to setting an alarm based on the passage of time (for example, an alarm that fires every 30 seconds).
  • Real time clock (RTC): uses UTC (wall clock) time. It is better suited for alarms that needs to fire at a particular time of day. The use of RTC alarms can have some drawbacks: the app may not translate well to other locales, and if the user changes the device's time setting, it could cause unexpected behavior in your app.
If the device's screen is off (device in asleep state), alarms don't fire. Because of this, both types have a "wakeup" version, which says to wake up the device's CPU if the screen is off. This ensures that the alarm will fire at the scheduled time. Note, however, that, in case of Elapsed real time alarms, the elapsed time includes any time during which the device was asleep.

Cancel an alarm

All alarms are cancelable. To cancel an alarm, call cancel() on the AlarmManager, passing in the PendingIntent you no longer want to fire.

Alarms and device shut down

By default, all alarms are canceled when a device shuts down. To prevent this from happening, you can design your application to automatically restart a repeating alarm if the user reboots the device. Here are the steps:

1) Set the RECEIVE_BOOT_COMPLETED permission in your application's manifest. This allows your app to receive the ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting (this only works if the app has already been launched by the user at least once):

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

2) Implement a BroadcastReceiver to receive the broadcast:
class SampleBootReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
if (intent.action == "android.intent.action.BOOT_COMPLETED") {
// Set the alarm here.
}
}
}

3) Add the receiver to your app's manifest file with an intent filter that filters on the ACTION_BOOT_COMPLETED action:

<receiver android:name=".SampleBootReceiver"
    android:enabled="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

Notice that in the manifest, the boot receiver is set to android:enabled="false". This means that the receiver will not be called unless the application explicitly enables it. This prevents the boot receiver from being called unnecessarily. You can enable a receiver (for example, if the user sets an alarm) as follows:

val receiver = ComponentName(context, SampleBootReceiver::class.java)

context.packageManager.setComponentEnabledSetting(
    receiver,
    PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
    PackageManager.DONT_KILL_APP
)

Once you enable the receiver this way, it will stay enabled, even if the user reboots the device. In other words, programmatically enabling the receiver overrides the manifest setting, even across reboots. The receiver will stay enabled until your app disables it. You can disable a receiver (for example, if the user cancels an alarm) as follows:

val receiver = ComponentName(context, SampleBootReceiver::class.java)

context.packageManager.setComponentEnabledSetting(
    receiver,
    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
    PackageManager.DONT_KILL_APP
)

Impacts of Doze and App Standby

Doze and App Standby were introduced in Android 6.0 (API level 23) in an effort to extend device battery life. When the device is in Doze mode any standard alarms will be deferred until the device exits Doze mode or a maintenance window opens. If you must have an alarm fire even in Doze mode you can use either setAndAllowWhileIdle() or setExactAndAllowWhileIdle(). Your app will enter App Standby mode when it is idle, meaning the user has not used it for a period of time and the app does not have a foreground process. When the app is in App Standby alarms are deferred just like in Doze mode. This restriction is lifted when the app is no longer idle or if the device is plugged in to a power supply.


Source: Schedule repeating alarms  |  Android Developers