Google在Android 5.0中引入JobScheduler来执行一些需要满足特定条件但不紧急的后台任务,APP利用JobScheduler来执行这些特殊的后台任务时来减少电量的消耗,使用JobScheduler的时候需要把待执行的后台任务封装到JobService中提交。
JobService继承自Service,并且是一个抽象类。在JobService中有两个抽象方法onStartJob(JobParameters)和onStopJob(JobParameters)。onStartJob在JobService被调度到的时候会执行,我们只需要继承JobService然后重写onStartJob方法,并在里面执行我们的后台任务就可以了。
public class MyJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
当任务开始时会执行onStartJob(JobParameters params)方法,这个方法返回一个boolean值。如果返回值是false,系统假设这个方法返回时任务已经执行完毕。如果返回值是true,那么系统假定这个任务正要被执行,这里就是我们需要自己写的任务执行逻辑了。当任务执行完毕时你需要调用jobFinished(JobParameters params, boolean needsRescheduled)来通知系统。
为什么我不设置 jobFinished(jobParameters,true)呢?这样不就重复执行了,这里确实是可以重复(应该说是重试)执行,但是只有是在特定场景下定时任务执行失败了,然后再次重复调度上次失败(跟上次失败的执行条件一致)的任务,而且这个调度周期是线性增长的,每次失败后下一次执行的时间间隔就会变长,所有不是执行间隔相同的定时任务。
当系统接收到一个取消请求时,系统会调用onStopJob(JobParameters params)方法取消正在等待执行的任务。很重要的一点是如果onStartJob(JobParameters params)返回false,那么系统假定在接收到一个取消请求时已经没有正在运行的任务。换句话说,onStopJob(JobParameters params)在这种情况下不会被调用。需要注意的是这个job service运行在你的主线程,这意味着你需要使用子线程,或者一个异步任务来运行耗时的操作以防止阻塞主线程。
接下来我们创建JobScheduler
private void startJobScheduler(Context context){
JobScheduler mJobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(jobId,new ComponentName(context,MyJobService.class));
builder.setPeriodic(5000);//执行周期
builder.setPersisted(true);//设备重启以后是否重新执行任务
//以下约束条件要至少满足一个,否则调用JobInfo.Buidler的build方法时会抛异常IllegalArgumentException
builder.setMinimumLatency(3000);//任务运行最少延迟时间
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);//任何网络环境下都可以执行
builder.setOverrideDeadline(50000);//若到期还没有达到规定的条件则会开始执行
builder.setRequiresCharging(false);//是否在只有插入充电器的时候执行
builder.setRequiresDeviceIdle(false);//是否手机系统处于空闲状态下执行
if(mJobScheduler.schedule(builder.build())== JobScheduler.RESULT_SUCCESS){
List<JobInfo> jobInfos = mJobScheduler.getAllPendingJobs();
if(jobInfos!=null && jobInfos.size()>0){
for (JobInfo jobInfo:jobInfos){
Log.e(TAG,"任务:"+jobInfo.getId());
}
}
}
}
Android7.0的源码系统默认设置了一个最小间隔时间15分钟,在获取执行间隔时,会先比较最小间隔时间和设置的间隔时间,取其中大的那个。所以setPeriodic设置时间小于15分钟是不会生效的。setPeriodic设置值大于15分钟,Android7.0与Android7.0以下的版本无区别,都是按照设置执行周期正常执行。如果项目中要使用了小于15分钟的执行时间周期,我们可以使用setMinimumLatency(设置任务执行的最小延迟)来达到绕过7.0系统的限制。
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
builder.setMinimumLatency(5000);
}else{
builder.setPeriodic(5000);
}
如果你的应用想停止某个任务,你可以调用JobScheduler对象的cancel(int jobId)来实现;如果你想取消所有的任务,你可以调用JobScheduler对象的cancelAll()来实现。
最后一步了,在Manifest.xml文件里添加service
<service
android:name=".MyJobService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />