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手机声称支持关机闹钟,其实是”假关机“。一句话,没有做硬件支持,就没有关机闹钟。