Android上定时运行任务常用的方法有2种,一种方法用Timer+TimerTask,另一种是AlarmManager。

Timer

Android 的 Timer 类可以用来计划需要循环执行的任务,Timer 的问题是它需要用 WakeLock 让 CPU 保持唤醒状态,这样会大量消耗手机电量,大大减短手机待机时间。而一旦待机,任务可能就不会执行了。

Timer实现不是很准确,时间上是有误差的。

AlarmManager

AlarmManager 是 Android 系统封装的用于管理 RTC 的模块,RTC (Real Time Clock) 是一个独立的硬件时钟,可以在 CPU 休眠时正常运行,在预设的时间到达时,通过中断唤醒 CPU。

这意味着,如果我们用 AlarmManager 来定时执行任务,CPU 可以正常的休眠,只有在需要运行任务时醒来一段很短的时间。

这种实现通常要选择RTC_WAKEUP才能达到这样的效果,这是需要注意的!

AlarmManager执行很准确,当然为了“更节能”也有不准确的执行方法:

    /***
     * Schedule a repeating alarm that has inexact trigger time requirements;
     * for example, an alarm that repeats every hour, but not necessarily at
     * the top of every hour.  These alarms are more power-efficient than
     * the strict recurrences supplied by {@link# setRepeating}, since the
     * system can adjust alarms' phase to cause them to fire simultaneously,
     * avoiding waking the device from sleep more than necessary.
     * 
     * <p>Your alarm's first trigger will not be before the requested time,
     * but it might not occur for almost a full interval after that time.  In
     * addition, while the overall period of the repeating alarm will be as
     * requested, the time between any two successive firings of the alarm
     * may vary.  If your application demands very low jitter, use
     * {@link# setRepeating} instead.
     * 
     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or
     *             RTC_WAKEUP.
     * @param triggerAtTime Time the alarm should first go off, using the
     *                      appropriate clock (depending on the alarm type).  This
     *                      is inexact: the alarm will not fire before this time,
     *                      but there may be a delay of almost an entire alarm
     *                      interval before the first invocation of the alarm.
     * @param interval Interval between subsequent repeats of the alarm.  If
     *                 this is one of INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR,
     *                 INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY then the
     *                 alarm will be phase-aligned with other alarms to reduce
     *                 the number of wakeups.  Otherwise, the alarm will be set
     *                 as though the application had called {@link# setRepeating}.
     * @param operation Action to perform when the alarm goes off;
     * typically comes from {@link PendingIntent# getBroadcast
     * IntentSender.getBroadcast()}.
     *
     * @see android.os.Handler
     * @see# set
     * @see# cancel
     * @see android.content.Context# sendBroadcast
     * @see android.content.Context# registerReceiver
     * @see android.content.Intent# filterEquals
     * @see# ELAPSED_REALTIME
     * @see# ELAPSED_REALTIME_WAKEUP
     * @see# RTC
     * @see# RTC_WAKEUP
     * @see# INTERVAL_FIFTEEN_MINUTES
     * @see# INTERVAL_HALF_HOUR
     * @see# INTERVAL_HOUR
     * @see# INTERVAL_HALF_DAY
     * @see# INTERVAL_DAY
     */
    public void setInexactRepeating(int type, long triggerAtTime, long interval,
            PendingIntent operation) {
        try {
            mService.setInexactRepeating(type, triggerAtTime, interval, operation);
        } catch (RemoteException ex) {
        }
    }

二选一?

对于二者如何选用,各自有自己的应用场景吧。timer更轻便个人理解

应用运行期间执行的短时间的任务,可以选用timer+timertask。比如电话拨号程序中手机号码的查询匹配,不必每次输入一个数字都去查询,二三百毫秒用户无输入后再去查询这个需求,完全可以用Timer。

而对于几分钟甚至几十分钟的定时任务,如果用Timer的话就太浪费了。这个时候当然是选用AlarmManager。像应用普遍的Push需求其实都是客户端定时查询,只是一个时间比较长的定时循环任务。应用退出还得在查询,就要考虑耗电等情况。

再谈AlarmManager

AlarmManager可以用来实现闹钟,这个类实现系统警告服务,可以设定一个时间来完成指定的事情,只要在程序中设置了警报服务,就可以通过调用onReceive()方法执行你要做的事情,即使是待机状态,也不会影响运行。 原生系统中的type值可以是如下的值(一般选用RTC_WAKEUP):

/**
     * Alarm time in {@link System# currentTimeMillis System.currentTimeMillis()}
     * (wall clock time in UTC), which will wake up the device when
     * it goes off.
     */
    public static final int RTC_WAKEUP = 0;
    /**
     * Alarm time in {@link System# currentTimeMillis System.currentTimeMillis()}
     * (wall clock time in UTC).  This alarm does not wake the
     * device up; if it goes off while the device is asleep, it will not be
     * delivered until the next time the device wakes up.
     */
    public static final int RTC = 1;
    /**
     * Alarm time in {@link android.os.SystemClock# elapsedRealtime
     * SystemClock.elapsedRealtime()} (time since boot, including sleep),
     * which will wake up the device when it goes off.
     */
    public static final int ELAPSED_REALTIME_WAKEUP = 2;
    /**
     * Alarm time in {@link android.os.SystemClock# elapsedRealtime
     * SystemClock.elapsedRealtime()} (time since boot, including sleep).
     * This alarm does not wake the device up; if it goes off while the device
     * is asleep, it will not be delivered until the next time the device
     * wakes up.
     */
    public static final int ELAPSED_REALTIME = 3;

关于关机闹钟

首先说明下,关机闹钟是需要硬件支持的。Android原生系统是不支持关机闹钟的,市面上android手机很少有支持关机闹钟的,不是技术难点,是缺少硬件支持。 有些博客提到AlarmManager的一个关机闹钟的type:

AlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能。

而且被疯狂转载,完全没有考证过。。。不加思索的拷贝,并且越传越离谱。

其实只是某个特定机型(有硬件支持)定制系统中的type。从搜索结果来看,可能是ophone的一些机型。

最后再说一点,有些Android手机声称支持关机闹钟,其实是”假关机“。一句话,没有做硬件支持,就没有关机闹钟。