Schedule Exact Alarms with AlarmManager on Android

In Android Development precise task scheduling is essential for reliable and responsive applications. Recently in a project, I had to schedule a task at a precise time. I have used AlarmManager exact alarm in that project. I will share my learning and experience here.

Why Exact Alarm?

Exact Alarm is essential when your app requires a time-sensitive task to execute. InExact alarm depends on system optimization and exact alarm guarantee that it will be triggered at a specific time.

From Official doc:

InExact :

When an app sets an inexact alarm, the system delivers the alarm at some point in the future.

Exact:

The system invokes an exact alarm at a precise moment in the future.

Understanding Android Exact Alarm

The AlarmManager class supports time-based operation. AlarmManager can operate outside the lifetime of your application, so your app doesn't need to run in the background.

Implementation steps of Exact AlarmManager:

  • Acquiring AlarmManager: Get an instance of the AlarmManager service using getSystemService() method

  • Creating PendingIntent: Use PendingIntent class to define the intent that will be triggered when the alarm fires.

  • Schedule the Alarm: Set up the exact Alarm by using the exact alarm API from the AlarmManager class. There are 3 APIs for the exact Alarm

    • setExact(): This API invokes an alarm at a nearly precise time in the future if other battery-saving measures aren’t in effect

    • setExactAndAllowWhileIdle() : This invokes an alarm at a nearly precise time in the future, even if battery-saving measures are in effect

    • setAlrmClock() : This invokes an alarm at a precise time in the future. The system treats this as the most critical one.

  • Handling the Alarm: To handle an alarm you need to use a BroadCastReceiver. Ensure that your app's BroadcastReceiver receives the intent from the PendingIntent you created earlier.

Here is the simple code to schedule Alarm

First, create a BroadcastReceiver

class AlarmReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        Log.i("AlarmReceiver", "Alarm Received")
    }
}

Then schedule Alarm

   private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

   fun schedule(requestCode: Int , triggerTimeInMillis : Long) : Boolean {

        if (triggerTimeInMillis < System.currentTimeMillis()) {
            return  false
        }
        val pendingIntent = getPendingIntent(requestCode)
        val alarmClockInfo =AlarmClockInfo(triggerTimeInMillis, pendingIntent)
        alarmManager.setAlarmClock(alarmClockInfo, pendingIntent)
        Log.i("AlarmScheduler", "Alarm Scheduled")
        return true
    }

   private fun getPendingIntent(requestCode : Int) : PendingIntent {
        return PendingIntent.getBroadcast(
            context,
            requestCode,
            getIntent(),
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
    }

    private fun getIntent() : Intent {
        return Intent(context, AlarmReceiver::class.java)
    }

Register your BroadcastReceiver in AndroidManifest

<receiver android:name=".AlarmReceiver"/>

That's it

If your app targets Android 12 or higher you must declare “uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM”

If your app targets Android 13 (API level 33) or higher, you have the option to declare either the SCHEDULE_EXACT_ALARM or the USE_EXACT_ALARM permission.

Check official doc for more details.

There is an excellent article by Pablo Guardiola that explains different types of alarms. He also added a flow chart for making decisions about which API you should use.

Here is the flow

Flow chart for choosing Alarm API

Should consider

For less time-sensitive work you should use an inexact alarm. Check this use case where might not need an exact alarm.