解决AlarmManager时间不准
来源:互联网 发布:360解压缩for mac 编辑:程序博客网 时间:2024/05/02 02:51
AlarmManager.setRepeating()不精确, 重复Alarm都不好用了,想用的话每次重复设置吧!!!!
================================================================================
238 * <b>Note:</b> as of API 19, all repeating alarms are inexact. If your239 * application needs precise delivery times then it must use one-time240 * exact alarms, rescheduling each time as described above. Legacy applications241 * whose {@code targetSdkVersion} is earlier than API 19 will continue to have all242 * of their alarms, including repeating alarms, treated as exact.
=============================================================================解决AlarmManager时间不准
版权声明:本文为博主原创文章,未经博主允许不得转载。
公司项目已经渡过了研发阶段,现在进入了调试阶段(疯狂改Bug有木有!现在一看到有Bug的邮件过来,就想一拳打爆屏幕,当然也只是想想)。
言归正传! 在最近的Bug中发现一个问题,项目有用到预约的功能,所以就使用了AlarmManager来进行定时提醒的功能。当时开发这个功能的时候并没有发现会有这种Bug,原因是开发时只会预约一个来测试功能是否有实现,实现了就算完成,而这个问题恰好是有多个预约时才会发生的问题(这里的多个预约是指系统中有多个AlarmManager的定时,具体为什么这样说,下面我会提到),比如当我进行了10个预约,也就是设定了10个AlarmManager的时候,我让设备休眠(我用的Type是RTC_WAKEUP),依次观察10个通知的提醒。发现其中会有一两个通知并没有按照我设定的时间唤醒设备,而是会和与他时间相近的下一个预约同时出现(也就是发生了时间不精确的问题)。当时发现这个问题时以为是我在传递预约时间时发生了问题,就打Log查看了一下,发现并没有什么问题,既然时间没有问题,那很有可能是AlarmManager的问题,上网查了一下,在Android的文档中发现了端倪。
官方文档说从API19(android4.4)开始, 为了节能省电(减少系统唤醒和电池使用)。使用Alarm.set()和Alarm.setRepeating()已经不保证精确性(是不是突然一下就蒙了,不精确还怎么用?),不过Google怎么可能会做出这样不合理的设计呢!接着看就会发现其实Google还提供两个精确的Alarm方法,setWindow()和setExact(),看来问题是解决了。那顺便也分析一下AlarmManager吧,分析的过程中发现使用setAlarmClock这个方法也可以实现精准通知,但是有局限性,下面会说到。
浏览了一下官方文档和AlarmManager这个类,发现其实这个类很简单,就是定义了几个Type变量和set、cancle方法(其实AlarmManager的核心在AlarmManagerService中,这个一会儿再说)。这里只介绍一些经常使用的。
经常使用的变量:
其实主要就是分为两类,系统相对时间和绝对时间和是否唤醒CPU。
ELAPSED_REALTIME:使用相对时间,可以通过SystemClock.elapsedRealtime() 获取(从开机到现在的毫秒数,包括手机的睡眠时间),设备休眠时并不会唤醒设备。
ELAPSED_REALTIME_WAKEUP:与ELAPSED_REALTIME基本功能一样,只是会在设备休眠时唤醒设备。
RTC:使用绝对时间,可以通过 System.currentTimeMillis()获取,设备休眠时并不会唤醒设备。
RTC_WAKEUP: 与RTC基本功能一样,只是会在设备休眠时唤醒设备。
还有其他几个变量是针对API19和特殊方法使用的,这里就不具体介绍,可以通过文档查看。
经常使用的方法:
对于方法我不会把每一个都讲一遍,应为所有的set方法其实都是调用内部的一个private的方法setImpl(),只是不同的set方法传入的值不同而已,我就说一下setImpl这个方法。
可以看到setImpl这个方法内部也很简单,就是判断一下triggerAtMillis这个参数,然后调用mService.set方法。那这个mService又是什么呢?
在上面找发现了mService是一个叫IAlarmManager的service,这里变量是红色的,我用AndroidStudio无法再跟踪下去,但是看到这儿我们应该就想到安卓的AIDL通信方式,其实AlarmManager就是用的AIDl通信,从Alarm对象的获取我们也可以看出来
AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
是获取的系统服务,AlarmManager真正的实现都在FrameWork层的AlarmManagerService这个服务中。(从AlarmManager的构造方法中我们也可以看到他进行了API19版本的判断,这里我们还要注意mAlwaysExact这个参数,下面会用到)我先将setImpl的几个参数的含义说一下:
Type:就是我们上面说的那些变量。
triggerAtMillis:alarm的触发时间。
windowMillis:这个参数很繁琐,只有setWindow会主动设置,它的意思是设置一个时间区间,他会在triggerAtMillis的时间开始的这个区间内触发Alarm通知。普通的set()和setRepeating()方法会通过调用legacyExactLength()这个方法返回这个值:
这个方法就用到了我们上面说的mAlwaysExact这个变量,如果是小于API19的版本会使用
WINDOW_EXACT参数,这个参数是0(意思就是区间设置为0,那么就会按照triggerAtMillis这个时间准时触发,也就是精准触发)另一个参数WINDOW_HEURISTIC的值是-1,这个值具体的用法就要看AlarmManagerService具体的实现了,反正只要知道这个值是不精准就可以。剩下的其他set方法直接就将这个值设置为WINDOW_EXACT,那么那几个方法就都是精准通知了,除了setInexactRepeating方法将参数设置为WINDOW_HEURISTIC。
intervalMillis:间隔时间,用到Repeating类型的通知时使用,效果就类似我们设置的闹钟,过10分钟后提醒一次一样。
operation: 就是PendingIntent,没什么说的。
worksource:这个参数我也不知道什么意思,应为所有的方法都设置它为null,有知道的朋友可以告诉我一下。
alarmClock:设置AlarmClockInfo对象,看代码里这个对象实现了Parcelable接口,其实就是对triggerTime和PendingIntent的一个封装类。
那么参数就基本说完了,大家只需要不同方法传递不同参数就可以了。再说一下setAlarmClock这个方法,应为它用的是WINDOW_EXACT这个参数,所以这个方法也是精准的,不过他有一些局限性:
1:他只能在API21版本和之后的版本调用。
2:他的Type是固定的RTC_WAKEUP。
由于好奇心我又在网上查找了一下AlarmManagerService节能省电的原理是什么?通过看很多大神的分析,了解了原理,这里我简单总结一下。如果我们没有设置和使用精准通知的话,系统会把触发时间相近的Alarm放在同一个batch(看名字是一批的意思)中,然后每个bach根据时间排序放在mAlarmBatchs中,前面的就是先要触发的alarm。这就是原理,
也就是我们的Alarm会分为一批一批的一起触发,而不是每个Alarm都要触发。这就是我上面说的系统中有多个Alarm时会发生时间不准的现象,但如果系统中只有几个Alarm,并且他们的触发时间隔得很远,那么我们的Alarm就自己分为一批,触发还是会准的。
好了,对于AlarmManager的分析就到这里。有不对的地方希望大牛指导。
- 解决AlarmManager时间不准
- 解决AlarmManager时间不准
- 关于alarmmanager.set() or .setExact() 任务启动时间不准的一点想法(未实现)
- 解决校正PHP服务器时间不准的问题
- 怎样解决校正PHP服务器时间不准的…
- 看,时间不准啊!
- solr记录时间不准
- window时间不准设置
- cocos2dx定时器时间不准
- Quartz nextGivenMinuteDate时间不准
- AlarmManager计时不准,在手机灭屏后延迟的问题
- android的CountDownTimer开始时间不准或者不能倒计时到0的一种解决思路
- Delphi Sleep时间不准解决方案
- WinCE系统时间年份不准的原因
- Linux系统时间不准问题分析
- Linux系统时间不准问题分析
- 树莓派日期时间不准的修正方法
- 为什么你的linux时间总是不准
- 配置一个适合自己使用习惯的Android studio
- 如何正确获取百度定位Keystore,解决百度地图不显示问题
- UIWebView (NSURLProtocol)拦截js、css
- Android为控件原有background动态设置颜色
- ios流媒体直播整个框架介绍(HLS、RTSP)
- 解决AlarmManager时间不准
- 抗锯齿方法两种(其一:paint.setAntiAlias(ture);paint.setBitmapFilter(true))
- 跨域问题解决方案
- HDFS的运行机制
- PHP+apache+mysql集成
- 指针访问二维数组 数组指针
- activemq无法启动的问题,我的一个小方法
- 五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT) – 整理
- unity3d修改新建脚本模板