Android AlarmManager - RTC_WAKEUP vs ELAPSED_REALTIME_WAKEUP

86

Kann mir jemand den Unterschied zwischen AlarmManager.RTC_WAKEUPund erklären AlarmManager.ELAPSED_REALTIME_WAKEUP? Ich habe die Dokumentation gelesen, verstehe aber immer noch nicht wirklich die Auswirkungen der Verwendung übereinander.

Beispielcode:

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

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

Wie unterschiedlich werden die beiden Codezeilen ausgeführt? Wann werden diese beiden Codezeilen relativ zueinander ausgeführt?

Ich schätze Ihre Hilfe.

Camille Sévigny
quelle

Antworten:

140

AlarmManager.ELAPSED_REALTIME_WAKEUP Typ wird verwendet, um den Alarm seit dem Start auszulösen:

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

Der Alarm wird 10 Minuten nach dem Start des Geräts ausgelöst .

Es gibt einen Timer, der gestartet wird, wenn das Gerät hochfährt, um die Betriebszeit des Geräts zu messen. Dieser Typ löst Ihren Alarm entsprechend der Betriebszeit des Geräts aus.

Während, AlarmManager.RTC_WAKEUPden Alarm auslösen nach der Zeit der Uhr. Zum Beispiel, wenn Sie Folgendes tun:

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

Dies löst andererseits den Alarm in 30 Sekunden aus .

AlarmManager.ELAPSED_REALTIME_WAKEUPTyp wird im Vergleich zu selten verwendet AlarmManager.RTC_WAKEUP.

Rejinderi
quelle
1
Das ist was ich dachte. Ich brauchte nur eine Bestätigung. Wenn ich also so etwas gemacht habe: alarmManager.set (AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMills () + 30 * 1000, pendingIntent); Es könnten seltsame Dinge passieren (was ich hatte, bis ich bemerkte, dass es nicht so funktionierte, wie ich dachte.
Camille Sévigny
2
Bitte beachten Sie, dass der Code System.currentTimeMillis()anstelle von sein sollte System.currentTimeMills():)
HasanAboShally
17
"Der Typ AlarmManager.ELAPSED_REALTIME_WAKEUP wird im Vergleich zu AlarmManager.RTC_WAKEUP selten verwendet." Das sind Spekulationen und schlechte Ratschläge. Gemäß der Dokumentation: developer.android.com/training/scheduling/alarms.html "Wenn Sie Ihren Alarm lediglich in einem bestimmten Intervall (z. B. jede halbe Stunde) auslösen müssen, verwenden Sie einen der verstrichenen Echtzeittypen Im Allgemeinen ist dies die bessere Wahl. "
Jared Kells
1
Die Antwort von @ mborsuk ist besser und korrigiert diese Antwort: Sie sollten RTC nicht für die verstrichene Zeit verwenden, wie z thirtySecondsFromNow.
Micha F.
1
Ziemlich gute Erklärung :)! Ich möchte einen wichtigen Kommentar hinzufügen: In Bezug auf offizielle Dokumente von Android könnte die Verwendung von "AlarmManager.ELAPSED_REALTIME_WAKEUP" interessant sein, wenn es um eine Anwendung geht, die HTTP-Anforderungen an einen Server sendet, und Sie möchten keine generieren Laden Sie auf Ihren Webserver. Denken Sie an Tausende von Android-Geräten, die um 22:30 Uhr ein GET auf einem Webserver ausführen: Aufgrund der Tatsache, dass dies während der Startzeit des Geräts funktioniert, kann "AlarmManager.ELAPSED_REALTIME_WAKEUP" dazu führen, dass diese "Tausenden" Geräte Anfragen auslösen gleichzeitig Last vermeiden :).
ivanleoncz
107

Trotz der derzeit akzeptierten und hochgestimmten Antwort waren die Typen AlarmManager.ELAPSED_REALTIME * zusammen mit SystemClock.elapsedRealtime () immer zuverlässiger als die RTC-Uhren für Alarme und Timing.

Die Verwendung von ELAPSED_REALTIME_WAKEUP mit AlarmManager basiert auf einer monotonen Uhr ab dem Startzeitpunkt " und tickt auch dann weiter, wenn sich die CPU im Energiesparmodus befindet. Dies ist die empfohlene Grundlage für das allgemeine Intervall-Timing ". So,

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

Ihr PendingIntent wird in 1 Minute (60 * 1000 Millisekunden) ausgelöst.

Während AlarmManager.RTC_WAKEUP für die Standard- "Wand" -Zeit in Millisekunden seit der Epoche ist. So,

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

kann den Alarm auch in 60 Sekunden auslösen, jedoch nicht zuverlässig, da wie in der SystemClock-Dokumentation angegeben :

Die Wanduhr kann vom Benutzer oder vom Telefonnetz eingestellt werden (siehe setCurrentTimeMillis (lang)), sodass die Zeit möglicherweise unvorhersehbar vor- oder zurückspringt. Diese Uhr sollte nur verwendet werden, wenn die Korrespondenz mit realen Daten und Zeiten wichtig ist, z. B. in einem Kalender oder einer Weckeranwendung. Intervall- oder abgelaufene Zeitmessungen sollten eine andere Uhr verwenden. Wenn Sie System.currentTimeMillis () verwenden, sollten Sie die Intent-Broadcasts ACTION_TIME_TICK, ACTION_TIME_CHANGED und ACTION_TIMEZONE_CHANGED abhören, um herauszufinden, wann sich die Zeit ändert.

Außerdem bezog sich die Frage nur auf die * _WAKEUP-Alarme, aber lesen Sie auch die AlarmManager- Dokumentation dazu, um sicherzustellen, dass Sie verstehen, was die Weck- und Nicht-Weck-Alarme bieten.

mborsuk
quelle
Ihre Antwort ist großartig, aber in meiner Anwendung musste ich Alarme einstellen, die mit dem Datum / der Uhrzeit der realen Welt und nicht nur in 60 Sekunden übereinstimmen. In diesem Fall ist RTC_WAKEUP die beste Lösung für mich.
Camille Sévigny
8
Das ist in Ordnung, aber dies ist eine genauere Antwort auf die Frage und korrigiert die Dinge in der aktuell akzeptierten Antwort.
Mborsuk
+1 für diese Informationen, aber beachten Sie, dass elapsedRealtime()unter SystemClockstatt System. EDIT: ... Tägliches Abstimmungslimit erreicht ...
Jorge Fuentes González
Dies ist eine der besten Antworten in der dortigen Ausgabe. Ich suchte nach einer Nadel in einem 50 m hohen Heuhaufen (auch bekannt als "Fehler in meinem Code!") Und Ihre Antwort führte mich direkt zur Nadel!
AlxDroidDev
17

Nur eine Notiz. Sie können die Verfügbarkeit Millis anrufen:

long uptimeMillis =  SystemClock.elapsedRealtime();

Wenn Sie also in 30 Sekunden den Alarm auslösen und die Betriebszeit anstelle der normalen Uhr verwenden möchten, können Sie Folgendes tun:

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

Wenn Sie anstelle eines bestimmten Datums / einer bestimmten Uhrzeit nach einer verstrichenen Zeit suchen möchten, verwenden Sie am besten die Verfügbarkeit. Dies liegt daran, dass sich die vom Benutzer im Gerät festgelegte aktuelle Zeit ändern kann, wenn der Benutzer sie mithilfe der Einstellungen ändert.

Ena
quelle
3
+1 für den Hinweis, dass "wann immer Sie nach der verstrichenen Zeit suchen möchten". Perfekt macht Sinn.
Sulai
Nochmals nur zur Betonung: Meines Wissens nach wird dies in 30 Sekunden definitiv ausgelöst, es sei denn, etwas passiert wie das Herunterfahren des Geräts. Konkret denke ich, dass das Problem bei der Verwendung von RTC_WAKEUP darin besteht, dass es theoretisch in 15 Sekunden möglich ist, dass es an einem Samstag gegen Ende Oktober ungefähr 1 Uhr morgens wird und die Systemuhr 1 Stunde zurückliegt (in den USA und einem Großteil von Europa zumindest), dann wird der Alarm erst 1 Stunde und 30 Sekunden nach dem Einstellen ausgelöst.
Yannick
2

Ich habe dieses Problem in meinem eigenen Projekt so programmiert. im folgenden Code verwende ich

AlarmManager.ELAPSED_REALTIME_WAKEUP

Alarm zu einer bestimmten Zeit einstellen. Die Variable 'intentName' wird im intentFilter verwendet, um diesen Alarm zu empfangen. weil ich viele Alarme dieser Art abfeuere. wenn ich alle Alarme abbreche. Ich benutze die Methode Abbrechen. unten angegeben.

// um Alarme zu halten und bei Bedarf abzubrechen

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

Wo ist die Span-Funktion:

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

Alarmabbruchfunktion ist dies.

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

Einige wichtige Hinweise bei der Auswahl des zu verwendenden Alarms : (für wen, der die Stimmen bereits gelesen hat)

Das RTC_WAKEUP Todestal - Zeitänderung:
Wenn der Benutzer die Zeit manuell in die Vergangenheit geändert hat, wird der Alarm nicht ausgelöst, und in Zukunft wird der Alarm sofort ausgelöst, wenn er den RTCZeitstempel überschreitet.
Sie nicht verwenden Sie diesen Alarm alle Client - Seite Überprüfung / wichtige Aufgaben zu tun , weil es eine Chance zu scheitern haben.

Die WAKEUP Bedeutung (Marshmallow und höher)
Im Allgemeinen - nicht viel. Weckt das Gerät nicht auf, wenn idleoder während es in doze, dafür alarmManager.setExactAndAllowWhileIdleoder alarmManager.setAndAllowWhileIdle( Doze & Idle )

Nir Duan
quelle