介绍
JobScheduler是在Android 5.0添加的,它可以检测网络状态、设备是否充电中、低电量、低存储等状态,当所有条件都满足时就会触发执行对应的JobService来完成任务。同时具备了重试、定时执行、持久化任务(设备重启后可恢复任务)等功能。可谓是十分强大 JobScheduler的使用大致分为三步:
- 创建JobService类
- 创建一个JobInfo
- 获取JobScheduler系统服务执行任务
1 创建JobService
JobScheduler的原理大致是是通过监听手机状态,当条件满足时启动Service执行任务。 因此在使用JobScheduler之前,我们需要定义一个Service,当然并不是随随便便定义,而是需要派生自JobService。 只需要重写onStopJob和onStartJob即可。
1 | class DemoJobService: JobService() { |
同时,在manifest中注册时,还需要设置一个权限(否则会报错),如下
1 | <application |
2 创建JobInfo
JobInfo是对任务的描述,比如说需要监听哪些状态、重试策略、任务执行时间、是否持久化等等。 JobInfo.Builder的构造函数需要传入一个jobId,是Job的唯一标志,后续通过该jobId来取消Job。 通过Builder模式构造JobInfo。
1 | val jobInfo = JobInfo.Builder(1, ComponentName(packageName, DemoJobService::class.java.name)) |
JobInfo其他的设置方法:
1 | .setMinimumLatency(5000)//5秒 最小延时、 |
3 执行任务
最后通过getSystemService获取JobScheduler服务执行任务就可以了
1 | //执行任务 |
4 最后
JobScheduler上手还是比较简单的,由于本文是基于api23的源码,因此还有很多新功能没有在源码中展示出来,如setRequiresBatteryNotLow(设置Job对电量的要求)、setRequiresStorageNotLow(设置Job对存储空间的要求)等.
特性&适用
特性
- 支持在一个任务上组合多个条件
- 内置条件:设备待机、设备充电和连接网络
- 支持持续的job,这意味着设备重启后,之前被中断的job可以继续执行
- 支持设置job的最后执行期限
- 根据你的配置,可以设置job在后台运行还是在主线程中运行
适用
需要在Android设备满足某种场合才需要去执行处理数据:
- 应用具有可以推迟的非面向用户的工作(定期数据库数据更新)
- 应用具有当插入设备时希望优先执行的工作(充电时才希望执行的工作备份数据)
- 需要访问网络或 Wi-Fi 连接时需要进行的任务(如向服务器拉取内置数据)
- 希望作为一个批次定期运行的许多任务(s)
特征
- Job Scheduler只有在Api21或以上的系统支持。
- Job Scheduler是将多个任务打包在一个场景下执行。
- 在系统重启以后,任务会依然保留在Job Scheduler当中,因此不需要监听系统启动状态重复设定。
- 如果在一定期限内还没有满足特定执行所需情况,Job Scheduler会将这些任务加入队列,并且随后会进行执行。
使用Job Scheduler,应用需要做的事情就是判断哪些任务是不紧急的,可以交给Job Scheduler来处理,Job Scheduler集中处理收到的任务,选择合适的时间,合适的网络,再一起进行执行。把时效性不强的工作丢给它做。
源码分析
JobScheduler是系统服务JobSchedulerService,JobScheduler是一个抽象类;以下是JobScheduler的源码:
1 | public abstract class JobScheduler { |
JobScheduler的实现类是JobSchedulerImpl:
1 | public class JobSchedulerImpl extends JobScheduler { |
在代码中 调用mJobScheduler.schedule(job);其实是调了JobScheduler的实现类JobSchedulerImpl中的schedule方法;然后再调了mBinder.schedule(job);这个mBinder就是JobSchedulerService,调用了JobSchedulerService类里面IJobScheduler.Stub内部类的schedule方法; JobSchedulerService是在哪里启动的呢?先看一下的源码,从源码分析JobSchedulerService是一个系统服务;
1 | public class JobSchedulerService extends com.android.server.SystemService |
是系统服务那应该就是在 SystemServer启动的,先看一下SystemServer的源码;
1 | public final class SystemServer { |
手机开机启动会走SystemServer中的主函数main方法,main方法调用了run方法,下面是run方法中的代码:
1 | private void run() { |
从run方法可以看出,这里启动了一系列的系统服务,里面调用了startOtherServices()方法,那接下看一下startOtherServices方法,向下看:
1 | private void startOtherServices() { |
在startOtherServices方法方法中调用了mSystemServiceManager.startService(JobSchedulerService.class);这里就启动了JobSchedulerService服务;接下来我们分析JobSchedulerService的源码; 先看一下JobSchedulerService的构造方法:
1 | public JobSchedulerService(Context context) { |
创建了5个不同的StateController,分别添加到mControllers。 |类型|说明| |—|—| |ConnectivityController| 注册监听网络连接状态的广播| |TimeController| 注册监听job时间到期的广播| |IdleController| 注册监听屏幕亮/灭,dream进入/退出,状态改变的广播| |BatteryController| 注册监听电池是否充电,电量状态的广播| |AppIdleController| 监听app是否空闲|
前面提到调用mBinder.schedule(job);其实是调用了JobSchedulerService类里面IJobScheduler.Stub内部类的schedule方法;接下看一下这个方法:
1 | final class JobSchedulerStub extends IJobScheduler.Stub { |
从上面代码看出,是调用了调用JobSchedulerService中的schedule方法,好了,看一下JobSchedulerService中的schedule方法;
1 | public int schedule(JobInfo job, int uId) { |
从上面代码可以看出是通过Handler发消息,MSG_CHECK_JOB是目标源,看一下JobHandler 中的方法
1 | private class JobHandler extends Handler { |
通过Handler发消息,然后调用 maybeQueueReadyJobsForExecutionLockedH()方法,
1 | private void queueReadyJobsForExecutionLockedH() { |
这个方法主要是遍历将来要处理的工作任务然后一个个加到待处理工作任务集合中去;这个方法执行完后就会执行JobHandler中的maybeRunPendingJobsH()方法;
1 | private void maybeRunPendingJobsH() { |
从上面源码分析可以得出,这个方法通过遍历待处理任务集合,处理任务,这里调用了availableContext.executeRunnableJob(nextPending)方法,这个就是处理待处理任务的方法,接下来我们一起看看这个方法的源码,分析下:
1 | public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection { |
JobServiceContext是ServiceConnection,这个是进程间通讯ServiceConnection,通过调用availableContext.executeRunnableJob(nextPending)方法,会触发调用onServiceConnected,看到这里应该明白了,onServiceConnected方法中的service就是jobservice,里面还用了WakeLock锁,防止手机休眠,然后通过Handler发消息 调用了handleServiceBoundH()方法,
1 | /** Start the job on the service. */ |
从上面源码可以看出,最终是调用了jobService中的startjob方法, 这样就明白了,是如何触发调用jobService中的startjob方法的;
前面在JobSchedulerService中提到了控件类StateController类,这个是一个抽象类,有很多实现类,这个我只分析一个ConnectivityController实现类,其他都差不多,接下来分析一下ConnectivityController源码:
1 | public class ConnectivityController extends StateController implements |
上面是网络联接控制类ConnectivityController,当网络发生改变时,会触发网络连接改变广播,然后调用updateTrackedJobs(userid)方法,在updateTrackedJobs方法中,会判断网络是否有改变,有改变的会调 mStateChangedListener.onControllerStateChanged()方法;这样又调用了JobSchedulerService类中onControllerStateChanged方法:
1 | @Override |
在onControllerStateChanged方法中通过handler发消息,然后调用了maybeQueueReadyJobsForExecutionLockedH();
1 | private void maybeQueueReadyJobsForExecutionLockedH() { |
通过上面方法,把待处理的工作任务加到集合中,然后再调 maybeRunPendingJobsH();这个前面已提到过,就不再说了,一样的;