1、什么是Alarm?
简单来说可以理解成为闹钟,根本来说,是在某一个时间点,通过PendingIntent唤起某一个APP,执行指定的操作;
2、Alarm有哪几种?
根据“时间纬度”+“CPU唤起纬度”进行排列组合,因此一共有4种;
时间纬度:绝对时间(常规的年月日) or 相对时间(相对于开机之后,例如开机10分钟)
CPU唤起: 唤起 OR 不唤起
绝对时间+ 唤起CPU=AlarmManager.RTC_WAKEUP
绝对时间+不唤起CPU=AlarmManager.RTC
相对时间+ 唤起CPU=AlarmManager.ELAPSED_REALTIME_WAKEUP
相对时间+不唤起CPU=AlarmManager.ELAPSED_REALTIME
3、如何设置Alarm?
//1、创建intent
Intent intent = new Intent(ALARM_TEST);
//2.创建pendingIntent
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,0,intent,PendingIntent.FLAG_ONE_SHOT);
//3.获取系统AlarmManager
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(ALARM_SERVICE);
//4-1 使用set创建Alarm
alarmManager.set(AlarmManager.RTC,DateTool.nowInMs() ,pendingIntent);
//4-2 使用setRepeating创建Alarm
alarmManager.setRepeating(AlarmManager.RTC,DateTool.nowInMs(), 1000 ,pendingIntent);
//4-3 使用setInexactRepeating创建Alarm
alarmManager.setInexactRepeating(AlarmManager.RTC,DateTool.nowInMs(), 1000,pendingIntent);
3-1、AlarmManager中set、setRepeating、setInexactRepeating之间的差别
(1) AlarmManager.set: 一次性Alarm,在指定时间触发操作,需要指定其触发时间(triggerAtTime);
(2)AlarmManager.setRepeating:重复性Alarm,在指定时间触发操作,需要指定其触发时间(triggerAtTime),并且指明重复周期(interval);
(3)AlarmManager,setInexactRepeating:重复性Alarm,与setRepeating的区别是,存在一个优化逻辑;如果你的Alarm是RTC_WAKEUP or RTC类型,并且你的唤起周期(interval)是15分钟的整数倍,那么你的alarm首次执行执行时间并不一定是你设置的触发时间,系统会计算一个偏差,使其跟其他Alarm对齐,目的是尽可能的减少系统唤起次数,起到优化性能的作用;
4、Alarm系统是如何实现的?
所有Alarm实现都是在AlarmManagerService中;
4-1:Alarm存储:
分别使用4个List在内存中存储4种对应类型的Alarm信息,并且每一个List都是按照时间先后顺序排列的;
private final ArrayList
mRtcWakeupAlarms = new ArrayList
();
private final ArrayList
mRtcAlarms = new ArrayList
();
private final ArrayList
mElapsedRealtimeWakeupAlarms = new ArrayList
(); private final ArrayList
mElapsedRealtimeAlarms = new ArrayList
();
4-2:Alarm新增:
根据APP申明的Alarm类型,找到指定的List,根据唤起时间的先后顺序,插入到该List中;并且,通知内核,在该alarm需要唤起的时候,唤起AlarmThread
public void setRepeating(int type, long triggerAtTime, long interval,
PendingIntent operation) {
if (operation == null) {
Slog.w(TAG, "set/setRepeating ignored because there is no intent");
return;
}
synchronized (mLock) {
//1、创建Alarm
Alarm alarm = new Alarm();
alarm.type = type;
alarm.when = triggerAtTime;
alarm.repeatInterval = interval;
alarm.operation = operation;
//2、判断是否存在相同Alarm,是的话,移除它
removeLocked(operation);
if (localLOGV) Slog.v(TAG, "set: " + alarm);
//3. 保存Alarm到list中
int index = addAlarmLocked(alarm);
if (index == 0) {
//4、通知内核,新增Alarm
setLocked(alarm);
}
}
}
4-3:Alarm执行:
(1)定义一个名为AlarmThread的Thread,为一个while(true)实现的线程,等待内部唤起;
(2)唤起AlarmThread后,遍历4个List,搜索符合条件的Alarm,条件为:Alarm执行时间小于当前时间;
(3)在搜索Alarm过程中,如果Alarm符合条件,并且需要重复唤起该Alarm,计算该Alarm下次执行的时间,重新加入对应Alarm List;
(5)依次调用符合条件的Alarm中PendingIntent的send方法;
(6)凡是所有符合条件的Alarm中,存在一个唤起CPU的Alarm,那么CPU将会被唤起,直到所有Alarm的PendingIntent.send调用完毕;
5、注册两个PendingIntent完全相同,但是首次执行时间跟周期不同的Alarm,会怎么样?
在新增Alarm时,凡是检测到有PendingIntent完全相同的Alarm,一律之前设定的Alarm删除,依最后一次设定的Alarm为准;
6、注册一个Alarm,设置其执行时间在过去,那么它还会执行么?
(1)增加Alarm记录到相应的List中;
(2)唤起AlarmThread;
结果就是:立刻执行
6、移除一个APP,它设置的Alarm会怎么样?
改App设置的所有Alarm,都会被删除;
7、更新一个APP,它设置的Alarm会怎么样?
不做任何影响,被系统保留;
8、修改本机时间,已经设置的Alarm会怎么样?
AlarmThread会被唤起,然后所有符合条件的Alarm会被执行,并且Alarm下次执行的时间会成为:当前时间+该Alarm周期
9、重启手机,已经注册的Alarm会怎么样,下次启动还能用么?
由于Alarm是存储在内存中,并没有做持久化操作,因此重启后,所有注册的Alarm一律失效;