Android AlarmManager: RTC_WAKEUP frente a ELAPSED_REALTIME_WAKEUP


87

¿Alguien puede explicarme la diferencia entre AlarmManager.RTC_WAKEUPy AlarmManager.ELAPSED_REALTIME_WAKEUP? He leído la documentación pero todavía no entiendo realmente las implicaciones de usar uno sobre el otro.

Código de ejemplo:

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

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

¿Qué tan diferente se ejecutarán las dos líneas de código? ¿Cuándo se ejecutarán esas dos líneas de código entre sí?

Aprecio tu ayuda.

Respuestas:


140

AlarmManager.ELAPSED_REALTIME_WAKEUP type se utiliza para activar la alarma desde el momento del arranque:

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

de hecho, hará que la alarma suene 10 minutos después de que se inicie el dispositivo .

Hay un temporizador que comienza a funcionar cuando el dispositivo se inicia para medir el tiempo de actividad del dispositivo y este es el tipo que activa la alarma de acuerdo con el tiempo de actividad del dispositivo.

Considerando que, AlarmManager.RTC_WAKEUPactivará la alarma de acuerdo con la hora del reloj. Por ejemplo, si lo hace:

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

esto, por otro lado, disparará la alarma dentro de 30 segundos .

AlarmManager.ELAPSED_REALTIME_WAKEUPtype rara vez se usa en comparación con AlarmManager.RTC_WAKEUP.


1
Eso es lo que pensé. Solo necesitaba una confirmación. Entonces, si hice algo como esto: alarmManager.set (AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMills () + 30 * 1000, pendienteIntento); Pueden pasar cosas raras (que es lo que tuve hasta que me di cuenta de que no estaba funcionando como pensaba.
Camille Sévigny

2
Tenga en cuenta que el código debe ser en System.currentTimeMillis()lugar de System.currentTimeMills():)
HasanAboShally

17
"El tipo AlarmManager.ELAPSED_REALTIME_WAKEUP rara vez se usa en comparación con AlarmManager.RTC_WAKEUP". Esto es especulación y malos consejos. Según la documentación: developer.android.com/training/scheduling/alarms.html "Si simplemente necesita que su alarma se dispare en un intervalo particular (por ejemplo, cada media hora), use uno de los tipos de tiempo real transcurrido. En en general, esta es la mejor opción ".
Jared Kells

1
La respuesta de @ mborsuk es mejor y corrige esta respuesta: No debe usar RTC durante el tiempo transcurrido, como para thirtySecondsFromNow.
Micha F.

2
¡Bastante buena explicación :)! Me gustaría agregar un comentario importante: con respecto a los documentos oficiales de Android, usar "AlarmManager.ELAPSED_REALTIME_WAKEUP" podría ser algo interesante cuando se trata de una aplicación que envía solicitudes HTTP a un servidor y no desea generar ninguna. cargar en su servidor web. Piense en miles de dispositivos Android, que realizan un GET en un servidor web, a las 10:30 p. M.: Debido al hecho de que funciona durante el tiempo de arranque del dispositivo, "AlarmManager.ELAPSED_REALTIME_WAKEUP" podría hacer que estos "miles" de dispositivos activen solicitudes, no al mismo tiempo, evitando la carga :).
ivanleoncz

107

A pesar de la respuesta actualmente aceptada y votada, los tipos AlarmManager.ELAPSED_REALTIME * junto con SystemClock.elapsedRealtime () siempre han sido más confiables que los relojes RTC para alarmas y temporización.

El uso de ELAPSED_REALTIME_WAKEUP con AlarmManager se basará en un reloj monótono a partir del tiempo de arranque " y continúa marcando incluso cuando la CPU está en modo de ahorro de energía, por lo que es la base recomendada para el tiempo de intervalo de propósito general ". Entonces,

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

hará que su PendingIntent se dispare en 1 minuto (60 * 1000 milisegundos).

Considerando que, AlarmManager.RTC_WAKEUP es para el tiempo estándar de "muro" en milisegundos desde la época. Entonces,

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

también puede activar la alarma dentro de 60 segundos, pero no de manera confiable, porque como se indica en la documentación de SystemClock :

El reloj de pared puede ser configurado por el usuario o la red telefónica (ver setCurrentTimeMillis (largo)), por lo que el tiempo puede retroceder o avanzar de manera impredecible. Este reloj solo debe usarse cuando la correspondencia con fechas y horas del mundo real es importante, como en una aplicación de calendario o alarma. Las mediciones de intervalo o tiempo transcurrido deben usar un reloj diferente. Si está utilizando System.currentTimeMillis (), considere escuchar las transmisiones ACTION_TIME_TICK, ACTION_TIME_CHANGED y ACTION_TIMEZONE_CHANGED Intent para averiguar cuándo cambia la hora.

Además, la pregunta solo hizo referencia a las alarmas * _WAKEUP, pero consulte también la documentación de AlarmManager sobre eso para asegurarse de que comprende lo que proporcionan las alarmas de activación y no activación .


Su respuesta es excelente, pero en mi aplicación, necesitaba configurar alarmas que coincidieran con la fecha / hora del mundo real y no solo en 60 segundos a partir de ahora. En ese caso, RTC_WAKEUP es la mejor solución para mí.
Camille Sévigny

8
Está bien, pero esta es una respuesta más precisa a la pregunta y corrige cosas en la respuesta actualmente aceptada.
mborsuk

+1 para esta información, pero tenga en cuenta que elapsedRealtime()es inferior en SystemClocklugar de System. EDITAR: ... Se alcanzó el límite diario de votos ...
Jorge Fuentes González

Esta es una de las mejores respuestas al problema. Estaba buscando una aguja en un pajar de 50 m de altura (también conocido como "¡un error en mi código!"), ¡Y tu respuesta me llevó directamente a la aguja!
AlxDroidDev

17

Solo una nota. Puede obtener el tiempo de actividad millis llamando:

long uptimeMillis =  SystemClock.elapsedRealtime();

Entonces, si desea disparar la alarma dentro de 30 segundos y desea usar el reloj de tiempo de actividad en lugar del reloj normal, puede hacer lo siguiente:

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

Siempre que desee verificar el tiempo transcurrido en lugar de una fecha / hora específica, es mejor usar el tiempo de actividad. Esto se debe a que la hora actual establecida por el usuario en el dispositivo puede cambiar si el usuario la cambia usando la configuración.


3
+1 por señalar que debe usar eso "siempre que desee verificar el tiempo transcurrido". Tiene perfectamente sentido.
sulai

Una vez más, solo para enfatizar: tengo entendido que esto definitivamente se activará dentro de 30 segundos a menos que suceda algo como que el dispositivo se apague. Concretamente, creo que el problema con el uso de RTC_WAKEUP es que, en teoría, dentro de 15 segundos, es posible que se convierta en algo así como la 1 a. M. De algún sábado cerca de finales de octubre y el reloj del sistema retroceda 1 hora (en los EE. UU. Europa, al menos), por lo que la alarma no se dispara hasta 1 hora y 30 segundos después de haber sido configurada.
Yannick

2

Programé este problema en mi propio proyecto de esta manera. en el siguiente código que estoy usando

AlarmManager.ELAPSED_REALTIME_WAKEUP

para configurar la alarma a una hora específica. la variable 'intentName' se utiliza en intentFilter para recibir esta alarma. porque estoy disparando muchas alarmas de este tipo. cuando cancelo todas las alarmas. utilizo el método cancelar. dado en la parte inferior.

// para mantener alarmas y cancelar cuando sea necesario

     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);

donde la función span es esta:

 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);
}

La función de cancelación de alarma es esta.

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();
    }
}

1

Algunas notas importantes al elegir qué alarma usar : (para quién ya leyeron los votos a favor)

El RTC_WAKEUP valle de la muerte: cambio de hora:
si el usuario ha cambiado manualmente la hora al pasado, la alarma no se activará, y el futuro hará que la alarma se active inmediatamente si pasa la RTCmarca de tiempo.
No haga utilice esta alarma para realizar tareas importantes o de verificación del lado del cliente porque existe la posibilidad de que falle.

El WAKEUP significado (Marshmallow y superior)
En general, no mucho. No despertará el dispositivo cuando idleo mientras está en doze, por eso alarmManager.setExactAndAllowWhileIdleo alarmManager.setAndAllowWhileIdle( Doze & Idle )

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.