Android定时任务

AlarmManager

时隔将近1年多,博客都没有更新。实在是鸽了太久,都差点忘了CSDN的博客。最近这一年的积累更多实在项目里的点,相对于大块的知识点来说,项目里的点非常零碎,所以大篇幅的总结就比较少了。那么现在把云笔记的内容都搬上来和大家分享一下。

AlarmManager的用处

AlarmManger从名字就可以看出,这是一个闹钟管理器,就像是闹钟一样可以设置。
在4.4系统之前,通过AlarmManager进行定时任务,时间进行的非常准确。而在4.4之后,为了降低功耗,系统检测闹钟任务的频率降低,使得AlarmManager执行时间并不准确,会出现5分钟甚至更长的延时。

AlarmManager的设置

AlarmManager的关键点在于时间,任务以及执行方式。
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

设置时间
  • AlarmManager.RTC:硬件闹钟,不唤醒手机(也可能是其它设备)休眠;当手机休眠时不发射闹钟。
  • AlarmManager.RTC_WAKEUP:硬件闹钟,当闹钟发生时唤醒手机休眠;
  • AlarmManager.ELAPSED_REALTIME:真实时间流逝闹钟,不唤醒手机休眠;当手机休眠时不发射闹钟。
  • AlarmManager.ELAPSED_REALTIME_WAKEUP:真实时间流逝闹钟,当闹钟发躰时唤醒手机休眠;

实际上大体上可以分为RCT类时间和REALTIME类时间
- RCT:设备时间,也就是直接在手机标题栏中显示的时间。手机内常用的闹钟使用的就是这一类时间
- REALTIME:cpu运行时间,这个时间由设备开启开始计算。举个例子,REALTIME的10000L指的就是开机后10s的时间
这两类时间分别有唤醒和非唤醒两类。区别就在于在cpu休眠时是否唤醒cpu执行任务

设置任务

AlarmManager根据PendingIntent设置任务,可以说PendingIntent是AlarmManager的行动指挥,在AlarmManager中可以包含多个PendingIntent
广播标志,AlarmManager在到达指定的时间点时,可以通过PendingIntent执行响应。也就是说在指定时间点可以通过AlarmManager
启动一个Activity,BroadCast或是一个Service,在PendingIntent中放置需要的数据,达到定时任务的目的
需要注意的是,PendingIntent有一个requestCode需要唯一值进行设定

Intent intent_broadcast = new Intent("android.intent.action.FluxRecord");
intent_broadcast.putExtra("time", time);

PendingIntent pi = PendingIntent.getBroadcast(this, i, intent_broadcast, PendingIntent.FLAG_UPDATE_CURRENT);
list.add(pi);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
} else {
    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
}
执行方式

执行AlarmManager主要可分为两类,一次性任务和重复任务。
- 重复任务:非精确重复类型(不需要精确的间隔时间,系统将整合所有应用中的非精确重复闹钟,尽量平衡任务时间,降低cpu占用频率)

alarmManager.setInexactRepeating();
alarmManager.setRepeating();
  • 一次性任务:不同的系统版本,对于AlarmManager的唤醒机制存在不同的处理,版本越高越力求于降低cpu唤醒的频率。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
} else {
    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
}

JobService

Android 5.0提供的新的定时任务。不过和AlarmManager不同的是,并没有提供定时间点的任务,并且它的执行时间也并不算精确。
在5.0之后,google更提倡使用JobService,使用它更方便系统对这一类任务统一管理,尽量集中在cpu休眠状态下唤醒的时机。

启动/取消JobService
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    JobScheduler jobSchedule = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);

    PersistableBundle bundle = new PersistableBundle();
    bundle.putInt("id", 1);

    JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), CustomJobService.class.getName()))
                        .setExtras(bundle)            //传递数据
                        .setMinimumLatency(1000)      //延迟执行时间
                        .setOverrideDeadline(1000)    //最长延迟执行时间
                        .setPeriodic(1000)            //重复执行周期间隔
                        .setPersisted(true)           //需要android.permission.RECEIVE_BOOT_COMPLETED权限,并且不可与setMinimumLatency,setOverrideDeadline混用
                        .setBackoffCriteria(1000, JobInfo.BACKOFF_POLICY_EXPONENTIAL)   //任务失败重试机制(间隔时间,重试机制)
                        .build();

    int schedule = jobSchedule.schedule(jobInfo);
    if (schedule >= 0) {
        //任务正确执行
    }


//取消任务
//jobSchedule.cancel(jobId);
//jobSchedule.cancelAll();
}
JobService任务处理

onStartJob()的返回值。

  • 返回false时,任务处理完成后完全交给系统处理。在onStartJob中逻辑完成后,将会自动结束任务,而此时系统将不会调用onStopJob()。

  • 返回true时,任务处理完成后需要我们自行结束任务,否则应用的其他任务都不会执行,直到这一任务结束。在调用finishJob()后,任务将会结束并且调用onStopJob()方法。

JobService将会在主线程中运行,因此存在多线程处理时,我们会需要将onStartJob()返回值设为true,自己决定任务结束的时间,防止在onStartJob()中逻辑完成后Service直接结束。(例如需要Handle来处理逻辑时,返回true可以保证Handle部分代码完整的运行)

public class CustomJobService extends JobService {

    @Override
    //任务执行时调用
    public boolean onStartJob(JobParameters jobParameters) {
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        return false;
    }
}
AndroidMainfest中注册
<service
    android:name=".CustomJobService"
    android:permission="android.permission.BIND_JOB_SERVICE" />

总结

关于AlarmManager的研究还是不够深入,事实上在使用过程中AlarmManager在不同厂商不同机型下的表现不太相同,在部分机型下甚至有失效的情况出现(例如OPPOR9就出现过多次失效和延时过长),猜想是系统定制的时候有部分修改,但没有做分析所以我无法下定论。在试图用AlarmManager执行精确时间点任务时,4.4之前的版本运行可以没有太大问题,可以保证部分机型成功,当然部分机型还是存在问题。而在4.4之后的版本,普遍存在任务延迟甚至失效的情况,在之后有时间会研究5.0之后的闹钟源码寻求解决方式。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值