AlarmManager定时任务
定时任务在应用中最常见不过了,Android提供了很多定时的途径,短时间的延迟任务优先使用Handler的postDelay()方法,借助Timer,AlarmManager类设置定时任务。今天来讲一讲AlarmManager设置定时任务的用法。
Android官方文档:AlarmManager
1、AlarmManager
AlarmManager类提供对系统警报服务的访问。这些使您可以安排应用程序在将来的某个时间运行。警报响起时,系统会广播已为其注册的Intent,并在目标应用程序尚未运行时自动启动它。
1.1、执行时机
设备处于睡眠状态时会保留已注册的任务(如果设备在这段时间内关闭,可以选择将其唤醒),但是如果将手机关闭并重新启动,则定时任务将被清除。
应用正常退出后(onDestory()),设置的alarm有效,时间到了会执行。但是如果被“杀死”,那么设置的alarm将失效不会执行。
1.2、各版本区别
≥ API 19:为了省电节省资源,Alarm都是非准确的,操作系统会转换设置alarm的时间,来最小化唤醒设备的次数。如果想要设置准确的alarm可以调用setExact()方法
< API 19:targetSdkVersion小于19仍然会以准确的方式设置alarm
2、AlarmType
AlarmManager一共定义了四种类型的alarm,在设置定时alarm时候当做参数传入。
①RTC_WAKEUP:使用绝对时间System.currentTimeMillis(),在设备锁屏休眠时唤醒设备。
/**
* 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;②RTC:使用绝对时间System.currentTimeMillis(),设备锁屏休眠时并不会唤醒设备。
/**
* 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;③ELAPSED_REALTIME_WAKEUP:使用相对时间SystemClock.elapsedRealtime(),在设备休眠时唤醒设备。
/**
* 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;④ELAPSED_REALTIME:使用相对时间SystemClock.elapsedRealtime(),设备锁屏时并不会唤醒设备。
/**
* 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;小结:RTC使用的是绝对时间;ELAPSED使用的是开机以来的相对时间。WAKEUP在应用退出且手机锁屏的时候仍然会唤醒手机执行;不用WALEUP则应用退出且锁屏后不会执行定时任务,但是当应用没有退出在后台运行且锁屏时仍然会执行定时任务。
3、诸set方法
AlarmManager提供了很多设置定时alarm的方法,各有特点,大体分为两类方法分别用来设置精准任务和非精准任务,现在介绍常用的一些方法:
①非精准任务
public void set(int type, long triggerAtMillis, PendingIntent operation)
public void set(int type, long triggerAtMillis, String tag, OnAlarmListener listener,Handler targetHandler)
public void setRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)
public void setInexactRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)
public void setAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation)②精准任务
public void setWindow(int type, long windowStartMillis, long windowLengthMillis,PendingIntent operation)
public void setWindow(int type, long windowStartMillis, long windowLengthMillis, String tag, OnAlarmListener listener, Handler targetHandler)
public void setExact(int type, long triggerAtMillis, PendingIntent operation)
public void setExact(int type, long triggerAtMillis, String tag, OnAlarmListener listener, Handler targetHandler)
public void setAlarmClock(AlarmClockInfo info, PendingIntent operation)
public void setIdleUntil(int type, long triggerAtMillis, String tag, OnAlarmListener listener,Handler targetHandler)
public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation)下面介绍一些常用的,具体用法直接查看API文档或者源码。
3.1、set(...)
设置定时任务,该方法有两个重载:
①set (int type, long triggerAtMillis, PendingIntent operation)
设置定时任务的type,执行时间,还有到时间执行的PendingIntent操作。
②set (int type, long triggerAtMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler)
没有传入PendingIntent,而是传入OnAlarmListener回调,并且在传入的Handler上调用,如果targetHandler为null,那么将在应用程序的MainHandler上调用。
注意:从API 19开始,传递给此方法的触发时间被视为不准确;targetSdkVersionAPI 19之前的应用程序将继续获得先前的警报行为:所有计划的警报将被视为精确警报。
3.2、setExact(...)
设置精确的alarm定时任务,该方法同样有两个重载:
①setExact (int type, long triggerAtMillis, PendingIntent operation)
这个方法和上面的set()方法一样,唯一的区别是设置的时间是准确的,不允许OS调整优化时间。应用程序如果不像闹钟那样非常精准的话不建议调用该方法,会增加手机耗电。
②setExact (int type, long triggerAtMillis, String tag, AlarmManager.OnAlarmListener listener, Handler targetHandler)
同上。
3.3、setAndAllowWhileIdle(...) 慎用
设置电量较低的低功耗条件下的alarm任务,详细方法说明参考API文档。该方法也并非准确的,当低功耗的时候设置的任务会被重新安排,并且不那么准确,及时电量充足也不能保证准确性!
3.4、setExactAndAllowWhileIdle (...) 慎用
类似于setExact(...)方法,并且当系统处于低功耗模式也允许设置准确的定时alarm。发出警报后,该应用程序还将被添加到系统的临时白名单中大约10秒钟,以使该应用程序获得更多唤醒锁以完成其工作。
3.5、setRepeating (...)
setRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)方法设置重复的alarm,直到调用cancel(PendingIntent )清除为止。
注意:
①从API 19开始,所有重复警报都是不精确的。如果您的应用程序需要精确的交付时间,那么它必须使用一次性精确警报,并如上所述每次重新安排。targetSdkVersion早于API 19的旧版应用程序将继续将所有警报(包括重复警报)视为精确警报。
②设置重复alarm任务,必须使用PendingIntent,如果使用OnAlarmListener会抛出IllegalArgumentException("Repeating alarms cannot use AlarmReceivers")异常,查看源码可知。
3.6、setInexactRepeating (...)
setInexactRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)方法设置不太准确的重复alarm。
注意:从API 19开始,所有重复警报都是不精确的。由于自API 3以来就可以使用此方法,因此您的应用程序可以安全地调用它,并可以确保它在当前版本和较旧版本的Android上都具有类似的行为。
3.7、setWindow(...)
设置在给定访问内的定时alarm,在指定时间窗口内触发。
①setWindow (int type,long windowStartMillis,long windowLengthMillis, PendingIntent operation)
②setWindow (int type,long windowStartMillis,long windowLengthMillis,String tag,AlarmManager.OnAlarmListener listener,Handler targetHandler)
3.8、setAlarmClock(AlarmClockInfo info, PendingIntent operation)
setAlarmClock(AlarmClockInfo info, PendingIntent operation)设置【闹钟】,会在通知栏显示一个【闹钟】图标提醒用户。这种方法就像setExact(int, long, android.app.PendingIntent)但暗含 RTC_WAKEUP。
AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + 5000, null);
mAlarmManager.setAlarmClock(alarmClockInfo, pendingIntent);如果不是闹钟相关的应用尽量不要调用该方法,耗电比较多!
4、其它方法介绍
AlarmManager还提供了其它一些方法:取消定时任务、获取设置的下一个定时任务。
4.1、cancel(...)
①cancel(PendingIntent )
删除所有匹配的PendingIntent。任何意图与该意图相匹配(由定义Intent#filterEquals)的任何类型的警报都将被取消。
②cancel(OnAlarmListener )
删除AlarmManager中所有相关的警报OnAlarmListener。
4.2、getNextAlarmClock()
获取计划中的下一个alarm。获取通过调用setAlarmClock(AlarmManager.AlarmClockInfo, PendingIntent)方法设置的计划的alarm。
5、预设时间
AlarmManager中预定义了一些常用的时间值:
①INTERVAL_FIFTEEN_MINUTES:15分钟
/**
* Available inexact recurrence interval recognized by
* {@link #setInexactRepeating(int, long, long, PendingIntent)}
* when running on Android prior to API 19.
*/
public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000;②INTERVAL_HALF_HOUR:半小时
/**
* Available inexact recurrence interval recognized by
* {@link #setInexactRepeating(int, long, long, PendingIntent)}
* when running on Android prior to API 19.
*/
public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES;③INTERVAL_HOUR:1小时
/**
* Available inexact recurrence interval recognized by
* {@link #setInexactRepeating(int, long, long, PendingIntent)}
* when running on Android prior to API 19.
*/
public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR;④INTERVAL_HALF_DAY:半天
/**
* Available inexact recurrence interval recognized by
* {@link #setInexactRepeating(int, long, long, PendingIntent)}
* when running on Android prior to API 19.
*/
public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR;⑤INTERVAL_DAY:一天
/**
* Available inexact recurrence interval recognized by
* {@link #setInexactRepeating(int, long, long, PendingIntent)}
* when running on Android prior to API 19.
*/
public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY;6、使用AlarmManager
演示一下如何使用AlarmManager设置定时任务。
6.1、获取AlarmManager
AlarmManager属于系统服务,通过Context获取。至于为什么能获取到,在理解Window中有提到过。
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);6.2、PendingIntent意图
构造PendingIntent执行意图,传递给AlarmManager的set方法,作为定时任务达到时执行的动作。
关于PendingIntent的构造和使用方法见PendingIntent延迟意图。
6.3、设置计划任务
设置一个5s后,能够启动指定应用,并且在睡眠状态下能准确执行的定时alarm:
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.ss.android.article.news", "com.ss.android.article.news.activity.MainActivity"));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5000, pendingIntent);
相关博客:
Docs > Reference > AlarmManager">Android 开发者 > Docs > Reference > AlarmManager

