AlarmManager用法的注意事项

您所在的位置:网站首页 如何调闹钟和定时闹钟的区别 AlarmManager用法的注意事项

AlarmManager用法的注意事项

2024-06-05 18:18| 来源: 网络整理| 查看: 265

1、概述

最近在使用AlarmManager做周期性定时任务时发现在很短的时间内出现了重复的响应。 于是查看了下alarmmanager的说明并记录demo中alarm的表现方式。

2、Alarm Type

从android提供的闹钟方法来看,都要指定一个alarmtype。alarmtype是一个枚举常量,有四个取值,分别为 RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME。 这四个类型表明了闹钟的计时方式和响应时是否唤醒cpu。

2.1、RTC_WAKEUP

该字段android源码说明如下: rtc_wakeup 从描述可以看出,该类型表明闹钟的计时是以System.currentTimeMillis()的方式,也即相对1970年1月1日8点的毫秒数。 同时闹钟响应时,会唤醒设备CPU来响应执行闹钟事件。

2.2、RTC

rtc RTC的类型在计时方式与RTC_WAKEUP相同,不同的是如果设备在休眠,此种方式不会唤醒设备,而是等待下一次设备唤醒时再响应闹钟。此处之前有一个认知误区,我以为是设备在灭屏或锁定时不会响应此种类型的闹钟,而是解锁亮屏后才会响应。 但实际不是这样的,通过demo发现,在设备锁定灭屏后,依然可以响应闹钟。 其实这里描述的设备休眠指的是cpu,而不是设备灭屏,设备灭屏时cpu也可能在运转。可以参见如下回答。

You can’t set the time when the device will go to sleep because the system decides that. It’s actually “display sleep”. Imagine you’re downloading an apk from the Play store. Should the download stop just because you told the device to “sleep” after X seconds? Of course not.

2.3、ELAPSED_REALTIME_WAKEUP

在这里插入图片描述 ELAPSED_REALTIME_WAKEUP类型的闹钟与RTC_WAKEUP只是计时时间上的差别。 从说明上可以得知,此种闹钟类型的时间计算方式是设备启动以来的毫秒数(包括休眠),并且在闹钟响应时也会唤醒设备cpu。 例如我想在设备启动后10分钟执行一段逻辑,那么可以使用此种类型闹钟。

2.4、ELAPSED_REALTIME

elapsed_realtime 此种方式与ELAPSED_REALTIME_WAKEUP相对应,只是到了响应时间不会唤醒设备cpu。

3、单次的定时操作

单次的定时操作方法有精准和不精准两种类型,如下:

alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent); alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);

如果要使用精确的闹钟时,则需使用第一个接口。 对于set方法,源码解释如下:

Applications whose {@code targetSdkVersion} is before API 19 will continue to get the previous alarm behavior: all of their scheduled alarms will be treated as exact.

也即set方法在api 19以后是不精确的闹钟。这一点需要注意。

4、周期性的定时操作

使用周期性的闹钟定时接口如下:

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervalTime, pendingIntent);

但是需要注意的是从api 19开始,所有的周期性闹钟都不是精确响应的。 如果想要实现精确的周期性响应,那么应该使用单次精确闹钟,然后递归调用从而间接实现。

5、adb查看闹钟信息

在调试闹钟时,我们可以通过如下命令打印闹钟信息来调试逻辑。

adb shell dumpsys alarm

该命令可以打出很多有用的信息。 但是信息中的字段说明在google官方文档中没有说明。 可以参考此篇在stackoverflow上的回答。 里面有比较详细的字段解释。 该命令打印的内容一般比较多,可以考虑将内容输出到文本文件,然后通过搜索包名查找相应的内容。 ‘

6、triggerAtMillis参数问题

不论单次还是周期性闹钟,对应的方法中都有一个触发时间的参数,也即triggerAtMillis。我遇到有的项目传0的情况,之前很好奇传0是啥效果。看接口的文档说明是如果传一个过去的时间,那么闹钟会立刻响应(实际上这个立刻也没很快,实测每次时间都不等,有长有短)。 有了上面的adb查看闹钟信息后,通过如下demo来验证一下不同triggertime的表现。 在这里插入图片描述 上述代码执行完成后,通过adb打印闹钟信息,其中相关的闹钟信息如下: triggerAt0 从上述日志中可以看到,triggerAtMillis参数传0时,实际响应时间1970年1月1日。按照文档的说明,该闹钟会立刻响应。 实际也较快响应了。

但是在多次的测试中发现,大部份情况下,下一次的响应时间能够回到正确的未来时间。但偶尔也会出现不符合常理的现像。 如当前时间是2020年1月10日22点07分,那么下一次的时间是超过当前时间且当前时间是隔间5分钟的整数倍的最小时间值, 为2020年1月10日22点10分,下下次的响应时间就是22点15分,依此类推。 在这里插入图片描述 在正常情况下,当triggerAtMillis传0时,间隔时间为5分钟的情况下,响应的时间一般是 1970年01月01日 8点整, 2020年01月10日22点10分整(代码执行的时间为2020年01月10日07分),2020年01月10日22点15分等等。

但是,在某些情况下也会出现,响应了第一次的闹钟后,还未到下一次响应时间前又响应了一次。 如下: 在这里插入图片描述 也即比预期的多响应了一次。 暂时还不清楚android底层的设置逻辑。 终上,在设置闹钟的响应时间时尽量不要传0,可以使用System.currentTimeMillis()或SystemClock.elapsedRealtime()来代替。

7、设备重启后闹钟服务是否存在?

通过adb shell dumpsys alarm命令发现,设备重启后应用之前设置的闹钟服务是会被清掉的。 这一点需要注意。 这让我想到了闹钟应用的实现。 如果重启闹钟会被清掉,那么闹钟应用是怎么实现的呢?带着好奇,我粗略的阅读了一下google的时钟应用源码。 首先,闹钟应用会监听设备开机广播,如下: 在这里插入图片描述 接收到广播后,调用fixAlarmInstances方法,如下: 在这里插入图片描述 从方法名便可以推断可能是重设闹钟的。该方法的核心逻辑如下: 在这里插入图片描述 从上面的代码中可以看出,应用将设置到系统的闹钟取出,然后遍历比对时间响应的时间是否合法。 如果不合法,则删除该闹钟。 遍历完成后,再调用updateNextAlarm设置下一次的闹钟。

8、总结

1、闹钟在api 19及以后都是不精确的响应的。 2、闹钟类型中的RTC_WAKEUP及RTC的差别在于是否会唤醒设备cpu,但android设备灭屏后不一定马上进入休眠,这个过程是android底层控制的。 同理与ELAPSED_REALTIME_WAKEUP与ELAPSED_REALTIME。 3、精确类型的闹钟可以通过单次精确闹钟递归调用间接实现。 4、triggerAtMillis尽量避免传入0,可用System.currentTimeMillis()或SystemClock.elapsedRealtime()来代替。 5、设备重启后之前设置的闹钟会被清掉,如果有需要,则要重新调置。 6、闹钟可用adb shell dumpsys alarm命令来调试。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3