1 简介
JobScheduler(作业调度器)
是Android L提供的API,可以通过内置的某些条件在满足条件的情况下执行特定的任务,Google采用了Job的方式,每个需要后台处理的业务为一个Job,通过管理系统Job来提高资源利用率,从而提高性能,节省电源。
使用 JobScheduler
可以替代传统的 WakeLock
和 Alarm
运行app任务,可以将它看作“互相协作的WakeLock/Alarm”API。
每个app中的 WakeLock
和 Alarm
都是相互独立的,但是 JobScheduler
将设备的唤醒抽离至操作系统层面。因为 Alarm
和 WakeLock
受沙箱限制,所以无法与安装在设备上的其他应用相互协调。比如,设备上5个app每30分钟唤醒设备依次,则它们的唤醒几乎不可能同步,最终设备每小时会被唤醒10次。但由于 JobScheduler
是在系统层级,系统可以更有效地执行所有的调度工作,每小时唤醒设备的次数也会减少。
除了调度设备唤醒,JobScheduler
还允许设定获取数据的时间间隔,比如把唤醒时间限制在8分钟之后10分钟之内,这给操作系统留出一定的调整范围,让系统可以更好地协调唤醒以达到省电的目的。
JobScheduler支持的内置条件处理:
- 网络:指定在哪种网络状态下启动Job
- 电源:指定电源是否连接、电源大小情况启动Job
- 设备:指定设备是否处于空闲状态启动Job
- 存储:指定存储大小情况启动Job
2 JobScheduler API
JobScheduler关联三个API:
- JobService:被JobScheduler启动的执行Job的服务
- JobInfo:Job所需满足的条件和参数
- JobScheduler:系统服务,用于启动指定的JobService
2.1 JobService
JobService
继承于Service,因此JobService同样是在主线程运行,如果需要执行耗时操作,需要放在子线程处理。
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class JobSchedulerService extends JobService {
/**
* 启动工作
*
* @return
*
* 如果返回true,代表执行的将会是一个耗时任务,工作将会在异步执行,在执行完Job后要手动调用jobFinished()结束Job,否则系统不会再入队其他Job执行,即JobScheduler的执行队列阻塞
*
* 如果返回false,代表处理的Job不是一个耗时任务
*/
@Override
public boolean onStartJob(JobParamters params) {
return false;
}
/**
* 结束工作
*
* 系统收到取消Job请求且这个Job仍然在执行,系统就会调用该方法,即onStartJob()要返回true且执行耗时的Job没有结束时会调用,否则不调用
*/
@Override
public boolean onStopJob(JobParamters params) {
return false;
}
}
注册JobService:
<service android:name=".JobSchedulerService"
android:permission="android.permission.BIND_JOB_SERVICE" />
2.2 JobInfo
JobInfo
是构建满足特定条件的Job执行参数信息。
private static final int JOB_ID = 1;
// JobSchedulerService是自定义的启动Job执行的服务
JobInfo.Builder jb = new JobInfo.Builder(JOB_ID, new ComponentName(getPackageName(), JobSchedulerService.class.getName()));
// 指定Job多少毫秒之后执行,与setPeriodic()互斥,同时使用会抛出异常
jb.setMinimumLatency(5000);
// 指定Job在多少毫秒之后执行无论条件是否满足,与setPeriodic()互斥
jb.setOverrideDeadline(10 * 1000);
// 是否系统重启后继续该Job执行,清单文件要添加权限android.permission.RECEIVE_BOOT_COMPLETED
jb.setPersisted(true);
// 指定Job每多少毫秒执行一次
jb.setPeriodic(3000);
// 指定启动Job时的网络类型
// JobInfo.NETWORK_TYPE_NONE:启动Job时不需要任何网络连接
// JobInfo.NETWORK_TYPE_ANY:启动Job时只要有网络就可以
// JobInfo.NETWORK_TYPE_NETWORK_TYPE_UNMETERED:启动Job时要连接wifi
jb.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
// 指定启动Job时是否需要连接电源
jb.setRequiresCharging(false);
// 指定启动Job时是否需要设别处于空闲状态
jb.setRequiresDeviceIdle(false);
// setRequiredNetworkType()、setRequiresCharging()、setRequiresDeviceIdle()同时使用时可能导致Job永远不会执行
// 这时需要设置setOverrideDeadline()确保Job在不满足条件时能被执行一次
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 指定启动Job时是否为低电源
jb.setRequiresBatteryNotLow(false);
// 指定启动Job时是否为低存储
jb.setRequiresStorageNotLow(false);
}
JobInfo jobInfo = jb.build();
2.3 JobScheduler
JobScheduler
是启动、取消任务的系统服务。
JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
// 如果启动成功将返回1,否则返回0
int result = jobScheduler.schedule(jobInfo);
if (result <= 0) {
// 取消Job
jobScheduler.cancel(JOB_ID);
jobScheduler.cancelAll();
// 获取Job
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
JobInfo pendingJob = jobScheduler.getPendingJob(JOB_ID);
}
List<JobInfo> allPendingJob = jobScheduler.getAllPendingJobs();
}
3 JobScheduler使用场景
我们使用 JobScheduler
主要是为了提高资源利用率从而达到省电的目的。
JobScheduler
主要处理的场景是:
- 在系统层级调度唤醒设备,避免设备中多个app不同步各自频繁唤醒设备
- 设定时间间隔获取数据
其他功能场景:
- 运行一个周期服务,维持网络连接
- 仅在不限流量的网络下运行某项工作(一般指wifi)
- 仅在设备空闲时运行(API中对空闲状态说得不是很明确,只是说设备“有时候”会处于空闲状态)
- 当设备接通电源时运行
- 连接频率衰减;延长后续连接的间隔时间