Site icon Treehouse Blog

Scheduling Time-Sensitive Tasks in Android with the AlarmManager

AlarmManager

Photo by Luis Llerena / CC0

In Android, the AlarmManager lets us schedule work to happen at a specific time. If your app has work to do and you’d like it to do that work even when the app isn’t running, then the AlarmManager might be a good solution.

But before we get started, a quick disclaimer. You should only use the AlarmManager when something needs to happen at a specific time. Anything else, and you should be using the JobScheduler. So unless you’re actually making an alarm or something like a clock that chimes every hour on the hour, then you should use the JobScheduler.

With that out of the way, let’s move on to learning about how to schedule alarms. To schedule an alarm in Android we’ll be using the AlarmManager which is a Service provided by the Android system. With an AlarmManager object, we can set an alarm by using one of the ‘set’ methods. Though you’ll likely stick with the ‘setExact’ or ‘setRepeating’ methods because these are the ones that deal with a specific time (the rest have been effectively replaced by the JobScheduler). Let’s take a look at ‘setRepeating’ to see what we’ll need to schedule an alarm.

setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)

The first thing we need is what type of alarm this is, which will be one of these options: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC, or RTC_WAKEUP. With the type we’re specifying two things: when the beginning of time is, and if the alarm should wake up the device. For the ‘ELAPSED’ options, the beginning of time was when the device turned on. Whereas for the ‘RTC’ options, the beginning of time was January 1st 1970 at midnight (UTC time).

So for the ‘triggerAtMillis’ parameter, depending on the alarm type, we’re either specifying the number of milliseconds since the device booted up or the number of milliseconds since 1970.

Moving on to the ‘intervalMillis’ parameter, this is how many milliseconds should be between each alarm.

Last but not least, the ‘operation’ is the PendingIntent you’d like to execute when the alarm fires. A PendingIntent can be used to fire off an Activity, BroadcastReceiver, or Service. And while typically you’ll use a BroadcastReceiver, you can also make a really annoying app by having a repeating alarm launch an Activity:

Once you’ve set your alarm, you might want to cancel it without force-closing the app. To do this, just use the AlarmManager’s ‘cancel’ method and pass in the PendingIntent you used to create the alarm.

Another thing you should know about alarms in Android is that they don’t persist when the device is turned off. So it’s up to us to keep track of which alarms are set and to reschedule them when the device is turned back on.

Luckily, the Android system broadcasts an ACTION_BOOT_COMPLETED Intent whenever the device has finished turning on. And we can setup a BroadcastReceiver to receive that Intent and reschedule our alarms accordingly:

Also, in order to receive the Intents, we’ll need to declare the ‘RECEIVE_BOOT_COMPLETED’ permission as well as add an IntentFilter to our receiver’s manifest entry:

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

<receiver android:name=".BootReceiver"> 
    <intent-filter>
        <action 
            android:name="android.intent.action.BOOT_COMPLETED"/>  
    </intent-filter> 
</receiver>

But now we’re running into another problem. What happens if the alarm wasn’t set and the user restarts their device? We’d be setting up an alarm that the user doesn’t even want!

Instead, a cool feature of Android is that you can enable and disable components (like BroadcastReceivers) as the app is running. So what we want to do, is enable our BootReceiver when an alarm is set, and disable it when an alarm is cancelled. We can do this by calling the ‘setComponentEnabledSetting’ method on the PackageManager:

It’s also a good idea to make sure that our BootReceiver starts disabled, which we can do in the manifest:

<receiver android:name=".BootReceiver"
        android:enabled="false">
    ...

Once that’s handled you should start to see your alarms behaving a lot more like you’d expect them to! If you’d like to see a simple implementation of all this check out this GitHub link. And if you’re interested in reading more about alarms or in learning about JobSchedulers check out the links at the bottom of the page.

As always, if you’re looking to learn more about Android development, then I suggest you start here. We’ll take you from novice to Android developer one step at a time and explain everything along the way. On the other hand, if you’re looking for something a bit more advanced then I strongly encourage you to check out our Kotlin course. It covers everything you need to know about Kotlin, and it does so by building a Solitaire app.

Resources


Become a certified Android Developer with the Treehouse Techdegree Program. Learn more today.

Scheduling Work with the JobScheduler

Exit mobile version