JobScheduler的使用分为:
基本使用代码如下:
自定义JobService,执行后台任务
public SimpleService extends JobService{
public boolean onStartJob(JobParameters params) {
// 在UI线程中执行。
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
// 在UI线程中执行。
Log.d(TAG,"onStopJob = "+DateUtil.getCurrentTime("yyyy-MM-dd HH:mm:ss"));
return true;
}
}
通过JobScheduler进行系统调度
private void startWorkJobService(){
// 获取系统服务 JobScheduler
JobScheduler scheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
if (scheduler == null){
return;
}
// 获取系统中的调度任务
List<JobInfo> jobInfoList = scheduler.getAllPendingJobs();
for (JobInfo jobInfo : jobInfoList){
if (jobInfo.getId() == ThirdService.JOB_ID){
scheduler.cancel(ThirdService.JOB_ID);
}
}
ComponentName jobService = new ComponentName(getContext(), ThirdService.class);
JobInfo.Builder builder = new JobInfo.Builder(ThirdService.JOB_ID, jobService);
JobInfo jobInfo = builder
.setPeriodic(3*1000)
.build();
scheduler.schedule(jobInfo);
System.out.println("开始执行work job "+jobInfo.isPeriodic());
}
继承JobService,必须要实现onStartJob
,‘onStopJob’。简要代码如下:
public SimpleService extends JobService{
public boolean onStartJob(JobParameters params) {
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.d(TAG,"onStopJob = "+DateUtil.getCurrentTime("yyyy-MM-dd HH:mm:ss"));
return true;
}
}
JobService 子类的方法’onStartJob’,‘onStopJob’ 是运行在UI主线程,因此需要注意的是两个函数都不能执行耗时操作,如果需要执行耗时操作,需要单独创建线程。
onStartJob
是在后台任务开始时调用这个方法。true
,表明onStartJob
,执行到return
语句时,该任务已执行完成,通知系统进行下一次的调度。由于’onStartJob’在UI线程,因此该任务不能是耗时任务。false
,表明’onStartJob’,执行到return
语句时,该任务未执行完成,一般这时候是耗时任务,通过线程中执行任务,此时,任务执行完成,需要调用接口jobFinished()
,表明任务执行完成,通知系统进行下一次的调度。onStartJob
入参JobParameters
,在构建JobInfo时会把参数通过Parameters传递给onStartJob
,比如jobId,序列化参数PersistableBundle
, 过程参数Bundle
等等。onStopJob
系统决定停止当前正在执行的后台任务时调用。jobFinished(JobParameters params, boolean wantsReschedule)
当JobService 子类执行耗时任务时,主动停止任务JobInfo
中的setBackoffCriteria
,来重新调度任务。JobInfo的主要功能是构造任务的约束条件以及相任务传递参数。
约束条件,我个人分为终端状态约束条件,时间相关约束条件两种
setRequiredNetworkType
,终端电量状态setRequiresCharging
,终端存储空间状态setRequiresStorageNotLow
,终端是否处于空闲状态setRequiresDeviceIdle
。重启后是否继续有效(本质是将任务序列化存储,并监听开机广播)这些约束条件,传入boolean的值或者固定的值,这些约束条件,只的是在特定情况发生,只要状态不满足就不会发生,也不会重试。setPeriodic
,非周期性任务setMinimumLatency
,setOverrideDeadline
。重试策略setBackoffCriteria
。setPeriodic
和setMinimumLatency
,setOverrideDeadline
不能同时设置。setMinimumLatency
,setOverrideDeadline
与重试策略setBackoffCriteria
搭配可以保证,任务尽量能够执行成功。代码如下JobInfo jobInfo = builder
// 进度调度后,最大延迟3秒,会进行调度
.setOverrideDeadline(3*1000)
.setBackoffCriteria(1000,JobInfo.BACKOFF_POLICY_LINEAR)
.build();
// 任务
public SimpleService extends JobService{
public boolean onStartJob(JobParameters params) {
new Thread(new Runnable() {
@Override
public void run() {
boolean flag = true;
// 判断任务状态
if (flag){
// 根据重试策略,再次执行
// 再次执行时间为当前时间+重试次数*1000 (毫秒)(重试时间根据不同的重试策略不同)
jobFinished(params,true);
}else {
// 任务执行完成,不在执行
jobFinished(params,true);
}
}
}).start();
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.d(TAG,"onStopJob = "+DateUtil.getCurrentTime("yyyy-MM-dd HH:mm:ss"));
// 在这里可以根据取消任务的原因来决定是否需要执行重试策略。
return true;
}
}
JobInfo jobInfo = builder
// 进度调度后,最大延迟3秒,会进行调度
.setPeriodic(3*1000)
.setBackoffCriteria(1000,JobInfo.BACKOFF_POLICY_LINEAR)
.build();
// 任务
public SimpleService extends JobService{
public boolean onStartJob(JobParameters params) {
new Thread(new Runnable() {
@Override
public void run() {
boolean flag = true;
// 判断任务状态
if (flag){
// 根据重试策略,再次执行
// 再次执行时间为当前时间+重试次数*1000 (毫秒)(重试时间根据不同的重试策略不同)
jobFinished(params,true);
}else {
// 表明当前任务执行完成,周期性执行下一个任务。
/**
周期性执行下一个任务分两种情况:
1. 当 android API 版本在21 ~ 24。为当前时间+周期间隔时间。
2. 当 android API 版本打与24,间隔时间如果任务执行时间不超过flexMillis,则还是以任务结束时间后加间隔时间开始再次调度,如果任务时间超过flexMillis,则当时间到达flexMillis,后再次计时调度。
3. 这就是 setPeriodic 一个传入参数和 两个传入参数的区别与注意事项。
**/
jobFinished(params,true);
}
}
}).start();
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.d(TAG,"onStopJob = "+DateUtil.getCurrentTime("yyyy-MM-dd HH:mm:ss"));
// 在这里可以根据取消任务的原因来决定是否需要执行重试策略。
return true;
}
}
传递参数的接口有
persisted
,则不能使用这个来传递参数。这些接口是
在构建JobInfo时,最为重要的是JobId。源码如下
public Builder(int jobId, @NonNull ComponentName jobService) {
mJobService = jobService;
mJobId = jobId;
}
jobId 必须是整个系统唯一的,不仅仅是当前应用唯一值。这就涉及两个问题,如果查询到整个系统的JobId,是否可以通过接口scheduler.getAllPendingJobs()
查询到,如果可以查询到是否可以通过接口cancel
其他应用创建的任务。这是不是涉及到一个权限问题。
问题1 如何保证jobId是全系统唯一的,如果不唯一有什么影响
通过测试发现。如果进程不相同,无法获得其他进程创建的job。这样有一个好处,其他进行也无法取消本进程创建的Job。
在Android7.0 以后,周期性的实际必须大于等于15分钟,这是比较难触发的,在开发过程中,不可能等15分钟调试一次,因此需要使用adb进行调试。目前发现在android7.0 以后的终端都有这个命令,但是命令的执行选项根据版本的不同会有所不同。
命令:adb shell cmd jobscheduler
根据命令对JobScheduler 进行测试。
Job scheduler (jobscheduler) commands:
help
Print this help text.
run [-f | --force] [-u | --user USER_ID] PACKAGE JOB_ID
Trigger immediate execution of a specific scheduled job.
Options:
-f or --force: run the job even if technical constraints such as
connectivity are not currently met
-u or --user: specify which user's job is to be run; the default is
the primary or system user
timeout [-u | --user USER_ID] [PACKAGE] [JOB_ID]
Trigger immediate timeout of currently executing jobs, as if their.
execution timeout had expired.
Options:
-u or --user: specify which user's job is to be run; the default is
all users
cancel [-u | --user USER_ID] PACKAGE [JOB_ID]
Cancel a scheduled job. If a job ID is not supplied, all jobs scheduled
by that package will be canceled. USE WITH CAUTION.
Options:
-u or --user: specify which user's job is to be run; the default is
the primary or system user
heartbeat [num]
With no argument, prints the current standby heartbeat. With a positive
argument, advances the standby heartbeat by that number.
monitor-battery [on|off]
Control monitoring of all battery changes. Off by default. Turning
on makes get-battery-seq useful.
get-battery-seq
Return the last battery update sequence number that was received.
get-battery-charging
Return whether the battery is currently considered to be charging.
get-battery-not-low
Return whether the battery is currently considered to not be low.
get-storage-seq
Return the last storage update sequence number that was received.
get-storage-not-low
Return whether storage is currently considered to not be low.
get-job-state [-u | --user USER_ID] PACKAGE JOB_ID
Return the current state of a job, may be any combination of:
pending: currently on the pending list, waiting to be active
active: job is actively running
user-stopped: job can't run because its user is stopped
backing-up: job can't run because app is currently backing up its data
no-component: job can't run because its component is not available
ready: job is ready to run (all constraints satisfied or bypassed)
waiting: if nothing else above is printed, job not ready to run
Options:
-u or --user: specify which user's job is to be run; the default is
the primary or system user
trigger-dock-state [idle|active]
Trigger wireless charging dock state. Active by default.