Android AlarmManager - RTC_WAKEUP vs ELAPSED_REALTIME_WAKEUP
Asked Answered
K

5

91

Can someone explain to me the difference between AlarmManager.RTC_WAKEUP and AlarmManager.ELAPSED_REALTIME_WAKEUP? I have read the documentation but still don't really understand the implication of using one over the other.

Example code:

    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
                     scheduledAlarmTime, 
                     pendingIntent);

    alarmManager.set(AlarmManager.RTC_WAKEUP, 
                     scheduledAlarmTime, 
                     pendingIntent);

How different will the two lines of code execute? When will those two lines of code execute relative to each other?

I appreciate your help.

Kuhl answered 9/5, 2011 at 14:22 Comment(0)
D
153

AlarmManager.ELAPSED_REALTIME_WAKEUP type is used to trigger the alarm since boot time:

alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 600000, pendingIntent);

will actually make the alarm go off 10 min after the device boots.

There is a timer that starts running when the device boots up to measure the uptime of the device and this is the type that triggers your alarm according to the uptime of the device.

Whereas, AlarmManager.RTC_WAKEUP will trigger the alarm according to the time of the clock. For example if you do:

long thirtySecondsFromNow = System.currentTimeMillis() + 30 * 1000;
alarmManager.set(AlarmManager.RTC_WAKEUP, thirtySecondsFromNow , pendingIntent);

this, on the other hand, will trigger the alarm 30 seconds from now.

AlarmManager.ELAPSED_REALTIME_WAKEUP type is rarely used compared to AlarmManager.RTC_WAKEUP.

Deloresdeloria answered 9/5, 2011 at 14:44 Comment(5)
That's what I thought. I just needed some confirmation. So if I did something like this: alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMills() + 30 * 1000, pendingIntent); weird things might happen (which is what I had until I noticed that it wasn't working like I thought.Fecteau
Please note that the code should be System.currentTimeMillis() instead of System.currentTimeMills() :)Usurp
"AlarmManager.ELAPSED_REALTIME_WAKEUP type is rarely used compared to AlarmManager.RTC_WAKEUP." This is speculation and bad advice. According to the documentation: developer.android.com/training/scheduling/alarms.html "If you simply need your alarm to fire at a particular interval (for example, every half hour), use one of the elapsed real time types. In general, this is the better choice."Modernistic
@mborsuk's answer is better and correcting this answer: You should not use RTC for elapsed time, like for thirtySecondsFromNow.Bunco
Pretty good explanation :)! I'd like to add an important comment: regarding to official documents from Android, using "AlarmManager.ELAPSED_REALTIME_WAKEUP" could be something interesting when it comes to an application that fires HTTP requests to a server, and you don't want to generate any load on your webserver. Think about thousands of Android devices, performing a GET on a webservers, at 10:30 PM: due to the fact that works over the boot time of the device, "AlarmManager.ELAPSED_REALTIME_WAKEUP" could make these "thousands" devices firing requests, not in the same time, avoiding load :).Mascot
C
116

Despite the currently accepted and up-voted answer, AlarmManager.ELAPSED_REALTIME* types along with SystemClock.elapsedRealtime() has always been more reliable than the RTC clocks for alarms and timing.

Using ELAPSED_REALTIME_WAKEUP with AlarmManager will rely on a monotonic clock starting from boot time "and continues to tick even when the CPU is in power saving modes, so is the recommend basis for general purpose interval timing". So,

alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
                 + 60*1000, pendingIntent);

will make your PendingIntent fire in 1 min (60*1000 milliseconds).

Whereas, AlarmManager.RTC_WAKEUP is for the the standard "wall" time in milliseconds since the epoch. So,

alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
                 + 60*10000, pendingIntent);

may also trigger the alarm 60 seconds from now, but not reliably, because as noted in the SystemClock documentation:

The wall clock can be set by the user or the phone network (see setCurrentTimeMillis(long)), so the time may jump backwards or forwards unpredictably. This clock should only be used when correspondence with real-world dates and times is important, such as in a calendar or alarm clock application. Interval or elapsed time measurements should use a different clock. If you are using System.currentTimeMillis(), consider listening to the ACTION_TIME_TICK, ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED Intent broadcasts to find out when the time changes.

Also, the question only referenced only the *_WAKEUP alarms but see also the AlarmManager documentation on that to make sure you understand what the wakeup vs non-wakeup alarms provide.

Compete answered 14/3, 2013 at 2:17 Comment(4)
Your response is great, but in my application, I needed to set alarms that coincided to real world date/times and not just 60 seconds from now. In that case, RTC_WAKEUP is the best solution for me.Fecteau
That's fine but this is a more accurate answer to the question and corrects things in the currently accepted answer.Compete
+1 for this info, but note that elapsedRealtime() is under SystemClock instead of System. EDIT: ... Daily vote limit reached...Shortridge
This is one of the best answers in the issue there. I was searching for a needle in a 50m high haystack (aka "a bug in my code!"), and your answer led me straight to the needle!Rainarainah
R
17

Just a note. You can get the uptime millis calling:

long uptimeMillis =  SystemClock.elapsedRealtime();

So if you want to fire the alarm 30 seconds from now, and you want to use the uptime clock instead of the normal clock, you can do:

long thirtySecondsFromNow =  SystemClock.elapsedRealtime() + 30 * 1000;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, thirtySecondsFromNow, pendingIntent);

Whenever you want to check for some elapsed time instead of a specific date/time, it's best to use the uptime. That's because the current time set by the user in the device can change if the user changes it using the settings.

Romelda answered 25/1, 2012 at 15:51 Comment(2)
+1 for pointing out to use that "whenever you want to check for elapsed time". Perfectly makes sense.Hafnium
Again just to stress: my understanding is that this will definitely fire 30 seconds from now unless something happens like the device shutting down. Concretely, I think the issue with using RTC_WAKEUP is that in theory, 15 seconds from now, it's possible that it becomes something like 1am on some Saturday near the end of October and the system clock goes back 1 hour (in the US and much of Europe, at least), so then the alarm doesn't actually trigger until 1 hour and 30 seconds after it was set.Rhotacism
R
2

I programmed this problem in my own project this way. in below code i am using

AlarmManager.ELAPSED_REALTIME_WAKEUP

to set alarm at a specific time. the variable 'intentName' is used in the intentFilter to receiver this alarm. because i am firing many alarms of this type. when i cancel all alarms. i use the method cancel. given at bottom.

//to hold alarms and cancel when needed

     public static ArrayList<String> alarmIntens = new ArrayList<String>();

//

    public static String setAlarm(int hour, int minutes, long repeatInterval,
        final Context c) {
    /*
     * to use elapsed realTime monotonic clock, and fire alarm at a specific time
     * we need to know the span between current time and the time of alarm.
     * then we can add this span to 'elapsedRealTime' to fire the alarm at that time
     * this way we can get alarms even when device is in sleep mood
    */
    Time nowTime = new Time();
    nowTime.setToNow();
    Time startTime = new Time(nowTime);
    startTime.hour = hour;
    startTime.minute = minutes;
    //get the span from current time to alarm time 'startTime'
    long spanToStart = TimeUtils.spanInMillis(nowTime, startTime);
    //
    intentName = "AlarmBroadcast_" + nowTime.toString();
    Intent intent = new Intent(intentName);
    alarmIntens.add(intentName);
    PendingIntent pi = PendingIntent.getBroadcast(c, alarms++, intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    //
    AlarmManager am = (AlarmManager) c
            .getSystemService(Context.ALARM_SERVICE);
    //adding span to elapsedRealTime
    long elapsedRealTime = SystemClock.elapsedRealtime();
    Time t1 = new Time();
    t1.set(elapsedRealTime);
    t1.second=0;//cut inexact timings, seconds etc
    elapsedRealTime = t1.toMillis(true);

    if (!(repeatInterval == -1))
        am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                elapsedRealTime + spanToStart, repeatInterval, pi);
    else
        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, elapsedRealTime
                + spanToStart, pi);

where span function is this:

 public static long spanInMillis(Time startTime, Time endTime) {
    long diff = endTime.toMillis(true) - startTime.toMillis(true);
    if (diff >= 0)
        return diff;
    else
        return AlarmManager.INTERVAL_DAY - Math.abs(diff);
}

alarm cancel function is this.

public static void cancel(Context c) {
    AlarmManager am = (AlarmManager) c
            .getSystemService(Context.ALARM_SERVICE);
    // cancel all alarms
    for (Iterator<String> iterator = alarmIntens.iterator(); iterator
            .hasNext();) {
        String intentName = (String) iterator.next();
        // cancel
        Intent intent = new Intent(intentName);
        PendingIntent pi = PendingIntent.getBroadcast(c, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        am.cancel(pi);
        //
        iterator.remove();
    }
}
Ruralize answered 27/4, 2013 at 7:20 Comment(0)
O
2

Some important notes when choosing which alarm to use:(for whom who already read the upvoted votes)

The RTC_WAKEUP death valley - time change:
If the user has manually change time to the past the alarm won't go off, and future will cause the alarm to go off immediately if it past the RTC timestamp.
Do not use this alarm to do any client side verification / important jobs because it have a chance to fail.

The WAKEUP meaning (Marshmallow and above)
In general - not much. Will not wakeup the device when idle or while in doze, for that alarmManager.setExactAndAllowWhileIdle or alarmManager.setAndAllowWhileIdle (Doze & Idle)

Othelia answered 20/12, 2016 at 10:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.