Set exact time for Alarm in Android Lollipop

I struggled with this for a little bit as I was porting my Android application over to use all the latest libraries after 5 years of no updates.

I used to use AlarmManager.setTime() to set my alarms. Particularly, this was for a timer application, where it was critical that the alarm is received by the application exactly at the right time. But once I upgraded to Lollipop, I realized that the alarm was not firing at the right time, and hence the timer app would not alert the user sometimes many seconds or minutes after it had expired.

It turns out that starting from Android Lollipop and later, AlarmManager.setTime() is no longer exact. This was mainly done to preserve battery. So now in Lollipop, you have to use AlarmManager.setExact() if you want the alarm to go off at the exact moment you set it for.

Note: it is discouraged to use setExact() everywhere, unless it’s justifiable for the purpose of the alarm you’re setting. For example in a timer countdown app, it’s important that the alarm goes of at exactly the correct moment (important in sports, for example). So battery life is slightly sacrificed for the purpose. Otherwise you should stick with setTime() and allow Android to figure out when to approximately fire the alarm (probably bundled together with other alarms at roughly the same time) so it can maximize battery. More information at: https://developer.android.com/reference/android/app/AlarmManager.html#setExact(int, long, android.app.PendingIntent)

In your code you can determine the OS version, and if it’s Lollipop or later, you can make it use setExact(), otherwise if older, use setTime() (since setExact wasn’t introduced till Lollipop):

AlarmManager alarmManager =
  (AlarmManager)
       context.getSystemService(Context.ALARM_SERVICE);

if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
   alarmManager.setExact(AlarmManager.RTC_WAKEUP,
         timer.stopTime,
         pendingIntent);
else
   alarmManager.set(AlarmManager.RTC_WAKEUP,
         timer.stopTime,
         pendingIntent);

And voila!