adding alarms to my android app

Well, the time had to come. WhenDidI logs reasonably well, so how about reminding the user when they haven’t done something in a while? Time to implement alarms.

It seems Android supplies an AlarmManager that can be used for this purpose. Alarms are passed to it as PendingIntent objects to be invoked at the time the alarm goes off. Alarms are only retained until the phone reboots – so I’ll have to take a page from the Alarms app that comes with the system and also set an alarm at system boot; when I get to that. For now, let’s just get this working at all!

There’s a fairly coherent tutorial to get started with. There’s the source code to Alarms within the Android source. And there are also some simple examples in the ApiDemos example supplied with the SDK. So this shouldn’t be too bad.

First, I’ll create an AlarmReceiver class that subclasses BroadcastReceiver. This will be used to create a notification and reset the alarm to the next time one’s due (if any) – this way we’ll only need one alarm set at a time, which should keep things simple. And in the interests of starting off simple, AlarmReceiver will just show a toast for now, as proof of concept. Alarm will need an entry in AndroidManifest.xml as a receiver. The one in ApiDemos looks like this:
        <receiver android:name=”.app.OneShotAlarm” android:process=”:remote” />
I haven’t noticed that android:process=”:remote” bit before, so I hope it doesn’t mind being cargo-culted to my app :-)

So, I created a quick test alarm functionality that I can use from any tracker to create an alarm specific to that tracker firing in five seconds. It works great – of course, for the first test all the alarm does is pop up a toast saying it fired. Let’s make it a little more interesting – have it fire a notification specific to the tracker, so I can see what it looks like when we have multiple alarms go off with multiple notifications. I add an extra to the intent for the alarm which includes the trackerId. The alarm receiver can read the ID and bring up the tracker from the database, and create a different notification based on that.

Here I notice a problem: sometimes I seem to be getting a previous intent instead of the one I sent (because the trackerId received doesn’t change when I send from a different tracker). Is the AlarmManager caching intents? I can’t find out much about this subject on the web. Perhaps it would help to cancel any previous alarms before creating a new one? That doesn’t seem to make a difference. Hmm, searching on that brings up a posting about the same problem.

[Returning to this after WEEKS – having a baby will really mess up your schedule!]

Turns out I had to overcome two problems. First, the alarm system will reuse previous PendingIntents according to how the alarm flags are set. I actually don’t remember exactly what this does now, will have to research again, but I ended up creating the PendingIntent like this:

        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                context, AlarmManager.RTC_WAKEUP, intent,
// keeps from re-using the previous intent:

Once the alarm intent was successfully invoked, I had a second problem with notifications reusing the PendingIntent given to them (I wanted to have a different notification for each tracker that has an alarm). To get around this I added an otherwise useless Data entry on the wrapped Intent to distinguish them (Extras are apparently not considered):

        Intent showTrackerIntent = new Intent(context, TrackerDetail.class)
                                            .putExtra(C.db_ID, trackerId)
                // the data keeps the PendingIntents distinguishable:

With this I could set different alarms that created different notifications for the same Activity with different inputs.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: