热门标签 | HotTags
当前位置:  开发笔记 > 程序员 > 正文

解决AlarmManager时间不准

AlarmManager.setRepeating()不精确,重复Alarm都不好用了,想用的话每次重复设置吧!!!!
AlarmManager.setRepeating()不精确, 重复Alarm都不好用了,想用的话每次重复设置吧!!!!
================================================================================
238 * Note: as of API 19, all repeating alarms are inexact. If your
239 * application needs precise delivery times then it must use one-time
240 * exact alarms, rescheduling each time as described above. Legacy applications
241 * whose {@code targetSdkVersion} is earlier than API 19 will continue to have all
242 * of their alarms, including repeating alarms, treated as exact.
=============================================================================
参考如下文章:
 

解决AlarmManager时间不准 标签: Android 1139人阅读 评论(1) 收藏 举报  分类:

公司项目已经渡过了研发阶段,现在进入了调试阶段(疯狂改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的分析就到这里。有不对的地方希望大牛指导。


推荐阅读
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 本文整理了Java中com.evernote.android.job.JobRequest.getTransientExtras()方法的一些代码示例,展示了 ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
  • 本文介绍了在Ubuntu 11.10 x64环境下安装Android开发环境的步骤,并提供了解决常见问题的方法。其中包括安装Eclipse的ADT插件、解决缺少GEF插件的问题以及解决无法找到'userdata.img'文件的问题。此外,还提供了相关插件和系统镜像的下载链接。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 如何使用PLEX播放组播、抓取信号源以及设置路由器
    本文介绍了如何使用PLEX播放组播、抓取信号源以及设置路由器。通过使用xTeve软件和M3U源,用户可以在PLEX上实现直播功能,并且可以自动匹配EPG信息和定时录制节目。同时,本文还提供了从华为itv盒子提取组播地址的方法以及如何在ASUS固件路由器上设置IPTV。在使用PLEX之前,建议先使用VLC测试是否可以正常播放UDPXY转发的iptv流。最后,本文还介绍了docker版xTeve的设置方法。 ... [详细]
  • Mono为何能跨平台
    概念JIT编译(JITcompilation),运行时需要代码时,将Microsoft中间语言(MSIL)转换为机器码的编译。CLR(CommonLa ... [详细]
  • 关于两个RTC时钟闹钟,求助?
    在系统启动2秒后,实时时钟(RTC)每3秒钟产生一个闹钟事件(Alarmevent),使系统进入停机模式以降低功耗设置实时时钟。 ... [详细]
  • mysql如何插入一列数据
    mysql插入一列数据的方法:首先打开终端;然后给表添加一列,代码为【altertableuseraddgendervarchar(2);】,其中列名为gender,类型为var ... [详细]
  • Harmony 与 Game Space 达成合作,在 Shard1 上扩展 Web3 游戏
    旧金山20 ... [详细]
  • 原文地址http://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/最开始时 ... [详细]
  • 【具体报错信息】ErrorparsingD:\android-sdks\system-images\android-22\android-wear\armeabi-v7a\devi ... [详细]
  • x86 linux的进程调度,x86体系结构下Linux2.6.26的进程调度和切换
    进程调度相关数据结构task_structtask_struct是进程在内核中对应的数据结构,它标识了进程的状态等各项信息。其中有一项thread_struct结构的 ... [详细]
author-avatar
放开丶那手
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有