Android AlarmManager - RTC_WAKEUP与ELAPSED_REALTIME_WAKEUP

时间:2011-05-09 14:22:38

标签: android alarmmanager

有人可以向我解释AlarmManager.RTC_WAKEUPAlarmManager.ELAPSED_REALTIME_WAKEUP之间的区别吗?我已经阅读了文档,但仍然没有真正理解使用其中一个的含义。

示例代码:

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

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

这两行代码的执行方式有多么不同?这两行代码何时相对于彼此执行?

感谢您的帮助。

5 个答案:

答案 0 :(得分:128)

AlarmManager.ELAPSED_REALTIME_WAKEUP类型用于在启动时触发警报:

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 :(得分:103)

尽管目前已接受并已投票,但AlarmManager.ELAPSED_REALTIME *类型以及SystemClock.elapsedRealtime()始终比报警和计时的RTC时钟更可靠。

对于AlarmManager使用ELAPSED_REALTIME_WAKEUP将依赖于从启动时间“开始的单调时钟,并且即使在CPU处于省电模式时也会继续打勾,因此通用间隔时间的推荐基础” 。所以,

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

将在1分钟内(60 * 1000毫秒)激活你的PendingIntent。

然而,AlarmManager.RTC_WAKEUP用于自纪元以来的标准“墙”时间(以毫秒为单位)。所以,

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

也可能在60秒后触发警报,但不可靠,因为SystemClock documentation中已提到:

  

挂钟可由用户或电话网络设置(请参阅   setCurrentTimeMillis(long)),所以时间可能会向后跳跃或   不可预测地转发。这个时钟只应在使用时使用   与现实日期和时间的对应很重要,例如   在日历或闹钟应用程序中。间隔或经过的时间   测量应使用不同的时钟。如果你正在使用   System.currentTimeMillis(),考虑听   ACTION_TIME_TICK,ACTION_TIME_CHANGED和ACTION_TIMEZONE_CHANGED   意图广播以找出时间的变化。

此外,该问题仅引用了* _WAKEUP警报,但另请参阅AlarmManager文档,以确保您了解唤醒与非唤醒警报提供的内容。

答案 2 :(得分:16)

请注意。您可以通过以下方式获得正常运行时间:

long uptimeMillis =  SystemClock.elapsedRealtime();

因此,如果您想在30秒后触发警报,并且您想使用正常运行时钟而不是正常时钟,则可以执行以下操作:

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

每当您想要检查一些经过的时间而不是特定的日期/时间时,最好使用正常运行时间。这是因为如果用户使用设置更改设备,用户在设备中设置的当前时间可能会发生变化。

答案 3 :(得分: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();
    }
}

答案 4 :(得分:0)

choosing which alarm to use时的一些重要说明:(对于已经阅读过投票的人而言)

RTC_WAKEUP 死亡谷 - 时间变化:
如果用户手动将时间更改为过去,则警报将不会响起,并且如果警报超过RTC时间戳,将来会立即关闭警报。
不要使用此警报执行任何客户端验证/重要作业,因为它有可能失败。

WAKEUP 含义(棉花糖及以上)
一般来说 - 并不多。在idledoze内,alarmManager.setExactAndAllowWhileIdlealarmManager.setAndAllowWhileIdleDoze & Idle

时,不会唤醒设备