Android AlarmManager - RTC_WAKEUP проти ELAPSED_REALTIME_WAKEUP


87

Хтось може пояснити мені різницю між AlarmManager.RTC_WAKEUPі AlarmManager.ELAPSED_REALTIME_WAKEUP? Я прочитав документацію, але все ще не розумію наслідків використання одного над іншим.

Приклад коду:

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

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

Наскільки різними будуть виконуватися два рядки коду? Коли ці два рядки коду виконуватимуться відносно один одного?

Я вдячний за твою допомогу.

Відповіді:


140

AlarmManager.ELAPSED_REALTIME_WAKEUP type використовується для спрацьовування будильника з часу завантаження:

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

насправді будильник спрацює через 10 хв після завантаження пристрою .

Існує таймер, який починає працювати, коли пристрій завантажується, щоб виміряти час безперебійної роботи пристрою, і це тип, який спрацьовує ваш будильник відповідно до часу роботи пристрою.

Тоді AlarmManager.RTC_WAKEUPяк спрацьовуватиме будильник відповідно до часу годинника. Наприклад, якщо ви робите:

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

це, з іншого боку, спрацює сигнал через 30 секунд .

AlarmManager.ELAPSED_REALTIME_WAKEUPтип використовується рідко порівняно з AlarmManager.RTC_WAKEUP.


1
Це те, що я думав. Мені просто потрібно було якесь підтвердження. Отже, якщо я зробив щось подібне: alarmManager.set (AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMills () + 30 * 1000, pendingIntent); можуть трапитися дивні речі (це те, що я мав, поки не помітив, що це працює не так, як я думав.
Каміль Севіньї,

2
Зверніть увагу, що код повинен бути System.currentTimeMillis()замість System.currentTimeMills():)
HasanAboShally

17
"Тип AlarmManager.ELAPSED_REALTIME_WAKEUP рідко використовується порівняно з AlarmManager.RTC_WAKEUP." Це спекуляції та погані поради. Відповідно до документації: developer.android.com/training/scheduling/alarms.html "Якщо вам просто потрібно, щоб будильник спрацьовував з певним інтервалом (наприклад, кожні півгодини), використовуйте один із минулих типів реального часу. загалом, це кращий вибір ".
Джаред Келлз

1
Відповідь @ mborsuk є кращою і коригує цю відповідь: Ви не повинні використовувати RTC протягом минулого часу, наприклад thirtySecondsFromNow.
Міха Ф.

2
Гарне пояснення :)! Я хотів би додати важливий коментар: щодо офіційних документів з Android використання "AlarmManager.ELAPSED_REALTIME_WAKEUP" може бути чимось цікавим, коли мова йде про програму, яка запускає HTTP-запити на сервер, і ви не хочете генерувати жодних завантажити на ваш веб-сервер. Подумайте про тисячі пристроїв Android, які виконують GET на веб-серверах о 22:30: через той факт, що це працює протягом часу завантаження пристрою, "AlarmManager.ELAPSED_REALTIME_WAKEUP" може робити ці "тисячі" пристроїв, що запускають запити, а не в той же час, уникаючи навантаження :).
ivanleoncz

107

Незважаючи на прийняту та прийняту на сьогодні відповідь, типи AlarmManager.ELAPSED_REALTIME * разом із SystemClock.elapsedRealtime () завжди були надійнішими, ніж годинники RTC для будильників та синхронізації.

Використання ELAPSED_REALTIME_WAKEUP з AlarmManager буде покладатися на монотонний годинник, починаючи з часу завантаження " і продовжує галочку, навіть коли центральний процесор перебуває в режимах енергозбереження, тому є рекомендаційною основою для загальних часових інтервалів ". Тому,

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

зробить ваш PendingIntent пожежею за 1 хв (60 * 1000 мілісекунд).

Тоді як AlarmManager.RTC_WAKEUP - це стандартний час "настінного" часу в мілісекундах з епохи. Тому,

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

також може спрацьовувати сигнал через 60 секунд, але не надійно, оскільки, як зазначено в документації SystemClock :

Настінний годинник може встановити користувач або телефонна мережа (див. SetCurrentTimeMillis (довгий)), тому час може непередбачувано стрибнути назад або вперед. Цей годинник слід використовувати лише тоді, коли важливим є листування з реальними датами та часом, наприклад, у календарі чи програмі-будильнику. Для вимірювання інтервалу або минулого часу слід використовувати інший годинник. Якщо ви використовуєте System.currentTimeMillis (), спробуйте прослухати ACTION_TIME_TICK, ACTION_TIME_CHANGED та ACTION_TIMEZONE_CHANGED трансляції намірів, щоб дізнатись, коли час змінюється.

Крім того, питання стосувалось лише тривог * _WAKEUP, але також дивіться документацію AlarmManager щодо цього, щоб переконатися, що ви розумієте, що забезпечують будильники проти непробудження.


Ваша відповідь чудова, але в моєму додатку мені потрібно було встановити будильники, які збігаються з датою / часом реального світу, а не лише через 60 секунд. У цьому випадку RTC_WAKEUP є найкращим рішенням для мене.
Каміль Севіньї

8
Це чудово, але це більш точна відповідь на запитання та виправлення речей у прийнятій зараз відповіді.
mborsuk

+1 для цієї інформації, але зверніть увагу, що замість цього elapsedRealtime()вказано менше . EDIT: ... Досягнуто ліміту щоденного голосування ...SystemClockSystem
Хорхе Фуентес Гонсалес

Це одна з найкращих відповідей у ​​випуску там. Я шукав голку в копиці сіна висотою 50 метрів (вона ж "помилка в моєму коді!"), І ваша відповідь привела мене прямо до голки!
AlxDroidDev

17

Просто примітка. Ви можете отримати безперебійний виклик:

long uptimeMillis =  SystemClock.elapsedRealtime();

Отже, якщо ви бажаєте спрацювати будильник через 30 секунд і хочете використовувати годинник безвідмовної роботи замість звичайного, ви можете зробити:

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

Всякий раз, коли ви хочете перевірити якийсь минулий час замість певної дати / часу, найкраще використовувати час безвідмовної роботи. Це тому, що поточний час, встановлений користувачем на пристрої, може змінюватися, якщо користувач змінює його за допомогою налаштувань.


3
+1 за вказівку використовувати "щоразу, коли ви хочете перевірити минулий час". Чудово має сенс.
сулай

Знову лише наголосимо: я розумію, що це точно спрацює через 30 секунд, якщо не трапиться щось подібне до вимкнення пристрою. Конкретно, я думаю, що проблема використання RTC_WAKEUP полягає в тому, що теоретично через 15 секунд можливо, що стане якось приблизно 1 ранку в якусь суботу близько кінця жовтня, а системний годинник повернеться на 1 годину назад (у США та більшій частині Принаймні в Європі), тож сигнал фактично спрацьовує лише через 1 годину 30 секунд після встановлення.
Yannick

2

Я запрограмував цю проблему у своєму власному проекті таким чином. у наведеному нижче коді, який я використовую

AlarmManager.ELAPSED_REALTIME_WAKEUP

щоб встановити будильник у визначений час. змінна 'intentName' використовується у intentFilter для отримання цього сигналу тривоги. тому що я спрацьовую багато сигналів цього типу. коли я скасовую всі будильники. я використовую метод скасування. внизу.

// утримувати будильники та скасовувати за потреби

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

де функція span - це:

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

це функція скасування тривоги.

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

Деякі важливі примітки при виборі, який будильник використовувати : (для кого вже читали голоси за

Долина RTC_WAKEUP смерті - зміна часу:
якщо користувач вручну змінив час на минуле, будильник не спрацює, а майбутнє спричинить негайний сигнал, якщо він минув RTCпозначку часу.
Не використовуйте цей будильник для будь-якої перевірки на стороні клієнта / важливих завдань, оскільки він має шанс вийти з ладу.

WAKEUP Сенс (Зефір і вище)
Загалом - НЕ так багато. Не активує пристрій, коли idleчи під час перебування doze, для цього alarmManager.setExactAndAllowWhileIdleабо alarmManager.setAndAllowWhileIdle( Дрімає та не працює )

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.