1. AndroidAlarm
1.1 简介
Alarm是android提供的定时器类,和Timer不同,使用Alarm可以在应用的生命周期之外定时触发特定操作。
1.2 构成要素
一个Alarm由以下4个要素构成:
(1)time type
Alarm有两种最基本类型,“elapsed real time”和“real time clock”,前者使用系统启动时的时间作为时间起点,后者使用UTC时间(1970 年 1 月 1 日0时)作为时间起点。所以“elapsedreal time”适用于间隔多长时间去触发一次操作,“real time clock”适用于在指定日期、时间(对时区敏感)去触发操作。
两种基本类型都扩展出了wakeup类型,wakeup类型的alarm触发时如果屏幕处在熄灭状态,cpu将会被唤醒。如果不使用wakeup类型,alarm将会在下次设备被唤醒时触发。
上述四种alarm类型标识如下:
ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC、RTC_WAKEUP。
(2)trigger time
触发时间,是从时间起点开始计算的毫秒数。
(3)interval (仅repeatingalarm需要)
间隔时间,单位为毫秒
(4)pendingintent
Pending intent 不仅用于指明Alarm触发后将要执行的操作,且用于唯一标识一个alarm,相同pending intent的alarm,新的将会覆盖旧的。
1.3 API
1.3.1 non-repeatingalarm
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() +
60 * 1000, alarmIntent);
例1-3-1
AlarmManager的set方法用于设置一次性定时器,三个参数分别为time type、trigger time、pending intent。例1设置了一个1分钟后触发的定时器。
1.3.2 repeatingalarm
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); // Set the alarm to start at 8:30 a.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 30); // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * 20, alarmIntent);
例1-3-2
AlarmManager的setRepeating方法用于设置经过间隔时间重复触发的定时器,相对于set方法,多了第三个参数interval(间隔时间)。
1.3.3 准确性
要注意的是,在Android4.4(API Level 19)以后,setRepeating方法设置的定时器触发时间并不是准确的,以下是官方文档中的说明:
原文地址:http://developer.android.com/training/scheduling/alarms.html
根据文档中的说明,setRepeating和setInexactRepeating之所以不准确,是系统会对他们进行统一调度,触发时间差不多的定时器会在同一时刻一次触发,以节省电量。
如果要使用能准确触发的定时器,我们要调用setExact()方法,该方法功能和set()方法一样,但在底层不允许系统去调整它的触发时间。
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() +
60 * 1000, alarmIntent);
例1-3-3
可惜的是,没有setExactRepeating()方法,也就是说准确且能重复的定时器只能由我们自己实现。实现的思路是:每次在定时器触发后设置一个新的定时器,触发时间增加一天。
1.3.4 误区
在测试setRepeating方法时,发现了一个误区,假定我设置定时器每日上午9点触发,那么定时器设置完后当日上午9点会准时触发,然后我会将日期往后调几日,测试其他日期上午9点是否会触发,每次调整时间后,定时器都会立即触发,而不是到9点。这是因为trigger time是一个毫秒数,而不是一个datetime值,当我们调整日期超过1天后,current timemillis一定大于trigger time,所以定时器会立即触发。
1.4 取消alarm
调用AlarmManager的cancel方法可以取消一个alarm,cancel方法需要传入pandingintent作为参数,代码如下:
// If the alarm has been set, cancel it. if (alarmMgr!= null) { alarmMgr.cancel(alarmIntent); }