一、需求
最近遇到一个需求,需要每天在某时间点触发执行一个任务,类似闹铃提醒,使用AlarmManager来实现。
二、实现
AlarmManager的基本使用大家可参考后面的文章,写的非常详细,在实现的过程中主要对闹钟的类型及相应的触发时间triggerTime(或者叫starttime)花了点时间研究了下。
1、闹钟的类型
-
AlarmManager.RTC_WAKEUP
表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,即当前系统时间,状态值为0; -
AlarmManager.RTC
表示闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间,状态值为1; -
AlarmManager.ELAPSED_REALTIME_WAKEUP
表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间(相对于系统启动开始),状态值为2; -
AlarmManager.ELAPSED_REALTIME
表示闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始),状态值为3; -
AlarmManager.POWER_OFF_WAKEUP
表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一,该状态下闹钟也是用绝对时间,状态值为4;不过本状态好像受SDK版本影响,某些版本并不支持;
2、AlarmManager的常用方法
- set(int type,long startTime,PendingIntent pi);
该方法用于设置一次性闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟执行时间,第三个参数表示闹钟响应动作。
- setRepeating(int type,long startTime,long intervalTime,PendingIntent pi);
该方法用于设置重复闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟首次执行时间,第三个参数表示闹钟两次执行的间隔时间,第三个参数表示闹钟响应动作。
3、AlarmManager.RTC_WAKEUP 和 AlarmManager.ELAPSED_REALTIME_WAKEUP区别
这个在参考文章2,stackoverflow中的一个提问中解释的比较清晰,大家可以直接看,我这把我自己理解的记录下:
-
AlarmManager.ELAPSED_REALTIME_WAKEUP:使用该类型的闹钟,设置的triggerTime需要使用相对时间,就是从设备开机后到现在的时间,即使设备断网或者用户手动修改时间,不会影响闹钟计时;
-
AlarmManager.RTC_WAKEUP:使用该类型的闹钟,设置的triggerTime需要使用绝对时间,即当前系统时间,因为系统时间会受到网络的影响,断网后时间不准了,且用户可以在系统设置中随意修改时间,这些都会影响闹钟的准确性。
代码举例1:
AlarmService是新建的Service,用来触发执行任务,代码比较简单就不贴了,大家新建service后别忘了在Manifest中注册。
下面代码实现1min后启动service,代码中有两种实现方式,均可以实现1min后提醒。
#MainActivity
private void startAlarm() {
Log.i(TAG, "startAlarm");
Intent intent = new Intent(this, AlarmService.class);
intent.setAction("com.alarm.notice");
pendingIntent = PendingIntent.getService(this, 0, intent, 0);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
//1min后触发,实现方式1
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 60 * 1000, pendingIntent);
//1min后触发,实现方式2
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ 60 * 1000, pendingIntent);
}
private void cancelAlarm() {
Log.i(TAG, "cancelAlarm");
alarmManager.cancel(pendingIntent);
}
代码举例2:每天到13:50点提醒,代码中两种实现方式,具体用哪一个大家根据自己需求来。
private void startAlarmRepeatEveryDay() {
Log.i(TAG, "startAlarmRepeatEveryDay");
Intent intent = new Intent(this, AlarmService.class);
intent.setAction("com.alarm.notice");
pendingIntent = PendingIntent.getService(this, 0, intent, 0);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
//设置提醒时间
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
//这里时区需要设置一下,不然会有8个小时的时间差
calendar.setTimeZone(TimeZone.getTimeZone("GMT+8"));
//设置每天为13:50点提醒
calendar.set(Calendar.MINUTE, 50);
calendar.set(Calendar.HOUR_OF_DAY, 13);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
long firstTime = SystemClock.elapsedRealtime();
long systemTime = System.currentTimeMillis();
long selectTime = calendar.getTimeInMillis();
//当前时间大于设置时间,说明今天提醒时间已经过去了,设置为明天的点来提醒
if (systemTime > selectTime) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
selectTime = calendar.getTimeInMillis();
}
long time = selectTime - systemTime;// 计算现在时间到设定时间的时间差
long triggerTime = firstTime + time;//系统当前的时间+时间差
//13:50点提醒,实现方式1
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP
, triggerTime, AlarmManager.INTERVAL_DAY, pendingIntent);
//13:50点提醒,实现方式2
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, selectTime,AlarmManager.INTERVAL_DAY, pendingIntent);
}
参考文章:
定时任务,AlarmManager使用
Android AlarmManager - RTC_WAKEUP vs ELAPSED_REALTIME_WAKEUP