Android定时任务的解决方案

定时任务的解决方案

  • SDK中的关键描述
  • 遇到的麻烦
  • 解决方案
  • 遇到的坑

SDK中的关键描述

Beginning in API 19, the trigger time passed to this method istreated as inexact: the alarm will not be delivered before thistime, but may be deferred and delivered some time later. The OS will use this policy in order to “batch” alarms together across the entire system,minimizing the number of times the device needs to “wake up” and minimizing battery use.

  • 从API 19以后,通过这个方法的触发时间将被视为不准确的报警不会在触发时间之前,会推迟到触发时间之后的一段时间。系统会尽可能的把时间统一起来批量报警,这样做都是为了能减少手机唤醒次数和电池的使用。

Legacy applications whose SDK is earlier than API 19 will continue to have all of their alarms,including repeating alarms,treated as exact.

  • 在API 19以前的系统上,闹钟触发会依然表现准确。

If an alarm is delayed (by system sleep, for example, for non_WAKEUP alarm types), a skipped repeat will be delivered as soon as possible.

  • 这是闹钟的一个特性,如果闹钟被延迟了,比如触发时间在8:00,但8:00时手机还未开机或者直接调整系统时间到8:00以后,被错过的触发时间会尽可能快的触发。(一开机则触发)

遇到的问题

项目中遇到一个问题,要做定时任务,时间较长,12小时一次,定时任务一般有三种解决方案:Timer、Handler、AlarmManager。Timer和Handler有两个明显的短板,一是所在进程崩溃或者被杀死后就失效了,还有一点是如果要做无限次数的定时任务时,这两者会常驻在内存中不能释放。AlarmManager则不存在这些问题,AlarmManagerService是一个系统级服务,他依赖RTC时钟。AlarmManagerService中管理着一个List,我们设置的闹钟会注册到这个数组中。等待线程会不停的循环判断我们的闹钟是否要激发。所以说我们添加一个激发点在性能上并不会带来多大影响。

API 19以前,AlarmManager常用的方案有两个,set()和setRepeat(),上文中讲过,这两个方法在API 19以后的系统中不再准确。

API 19以后增加了setExtra和setWindow,这两个方法都是一次性闹钟,并没有增加重复闹钟的方法。两个方法都是准确的,setWindow更加准确些,setWindow这个方法允许应用程序利用电池优化来自交货批处理即使它适度的及时性要求警报。

setExtra和setWindow在API 19以下不能使用,setRepeat在API 19以上表现不准。这就是我们现在遇到的问题。


解决方案

我们可以分版本解决,老版本用老办法,新版本用新办法。

  • 启动
if (Build.VERSION >= 19) {
    alarmManager.setWindow(AlarmManager.RTC_WAKEUP, Calendar.getTimeInMillis(),intervalMillis, PendingIntent);
} else {
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getTimeInMillis(), intervalMillis, PendingIntent);
}
  • API19 以上没有repeat方法,所以收到广播后再设置一次。
    @Override
    public void onReceive(Context context, Intent intent) {
      if(Build.VERSION >= 19){
        alarmManager.setWindow(AlarmManager.RTC_WAKEUP, Calendar.getTimeInMillis(),intervalMillis, PendingIntent);
      }
      //do anything
    }

遇到的坑

  • 这些方法的第一个参数都会传入一个闹钟类型,RTC表示的是绝对时间,而ELAPSED_REALTIME表示的是时间流,RTC可以通过修改手机时间触发闹钟事件,而ELAPSED_REALTIME必须通过真实时间的流逝,即使在休眠状态,时间也会被计算.官方是这么介绍的,而在使用中,有一部分手机在设置成RTC闹钟的情况下,调时间依然不能触发闹钟,同样需要真实的时间流逝,这可能和各家rom的修改有关。
    (做死的调时间,怎么调都不触发)
  • 上文说过,setRepeat()方法是不准确的,刚开始粗略估计可能推迟几秒到一分钟的程度吧,可用一款VIVO手机调试时,推迟时间居然长达3-5分钟。
    (等了一分钟,没反应,都要放弃了找问题,结果他触发了)
  • API 21以后,setRepeat()的重复周期的最小周期变为60秒。
    (一开始为了调试方便设置3秒,5秒的,一直没反应,满一分钟才触发)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值