JobScheduler是一个系统提供的框架,旨于在应用进程、而非系统进程内执行各种作业调度,其原理是启动通过bindservice
的方式启动对应应用进程的service,并在Service中进行作业。在执行一个Job时,将会使得系统持有一个WakeLock锁,以防止系统休眠进入Suspend。
在创建一个作业时,会设置多个约束条件,比如可以指定特定的网络、是否只在充电时执行作业等,JobScheduler框架会根据这些约束条件,智能地执行作业,并尽可能对作业进行批操作和推迟,以防止频繁唤醒系统而影响功耗,还可以指定该Job的执行的截至期限。如果不指定一个作业的截至期限,那么该作业可能会在任意一个时刻运行,这取决于JobScheduler的内部队列。
JobScheduler的使用比较简单,JobScheduler框架为应用提供了如下四个组件,通过这四个类的API可以让用户在应用中创建一个作业,并让系统对他进行调度。
JobScheduler类负责将应用需要执行的作业发送给框架,以准备对该应用Job的调度。JobScheduler是一个系统服务,可通过如下方式获取:
JobScheduler mJobScheduler = (JobScheduler) Context.getSystemService(Context.JOB_SCHEDULER_SERVICE).
JobInfo是传递给JobScheduler类的数据容器,它封装了针对调用应用程序调度作业所需的各种约束,也可以认为一个JobInfo对象对应一个作业,JobInfo对象通过JobInfo.Builder创建。它将作为参数传递给JobScheduler:
mJobScheduler.scheduler(mJobInfo);
JobInfo.Builder是JobInfo的一个内部类,顾名思义,它就是用来创建JobInfo的Builder类。
JobInfo.Builder mBuilder = new JobInfo.Builder(id,new ComponentName(this,MyJobService.class));
mJobInfo = mBuilder.build();
JobService是一个继承于Service的抽象类,他作为系统回调执行作业内容的终端,JobScheduler框架将通过bindService()
方式来启动该服务.因此,用户必须在应用程序中创建一个JobService的子类,并实现其onStartJob()
等回调方法,以及在清单文件中对它授予如下权限:
<service android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
public class MyJobService extends JobService {
@Override
public boolean onStartJob(final JobParameters params) {
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;//返回false表示停止后不再重试执行
}
}
别忘了在清单文件中配置权限:
<service android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
private ComponentName mServiceComponent;
//根据JobService创建一个ComponentName对象
mServiceComponent = new ComponentName(this, MyJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(mJobId++, mServiceComponent);
builder.setMinimumLatency(1000);//设置延迟调度时间
builder.setOverrideDeadline(2000);//设置该Job截至时间,在截至时间前肯定会执行该Job
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);//设置所需网络类型
builder.setRequiresDeviceIdle(true);//设置在DeviceIdle时执行Job
builder.setRequiresCharging(true);//设置在充电时执行Job
builder.setExtras(extras);//设置一个额外的附加项
//...
JobScheduler mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
mJobScheduler.schedule(builder.build());//调度Job
mJobScheduler.cancel(jobId);//取消特定Job
mJobScheduler.cancelAll();//取消应用所有的Job
下面根据创建时机,对以上提到的四个组件类提供的API进行总结。
JobInfo.Builder构造方法如下:
JobInfo.Builder (int jobId, ComponentName jobService)
int jobId
:指定一个jobId,该Id可用来取消Job等。
ComponentName jobService
:接收JobScheduler回调的终端ComponentName对象,应来自一个JobService对象。
设置重新调度Job的策略
initialBackoffMillis:
作业失败时最初等待的时间毫秒数;
backoffPolicy:
重新执行一个job的执行策略
当调用JobService.JobFinished(params,true)、JobService.onStopJob()返回true时,都会根据该方法设置的策略重新调度.
对具有setRequiresDeviceIdle()
的job设置该方法将引发异常。因为Doze状态下会对Job进行限制。
设置该job将执行的网络流量大小。
设置该值为true,则说明该job在当app处于前台状态或白名单时是非常重要的。
指定此job按提供的时间延迟。在定期job上,调用次方法将引发异常。
设置此Job的最大延迟调度,无论任何条件,即使有条件不满足,Job也将在该截止时间前运行。在定期job上,调用次方法将引发异常。
设置该Job为定期Job,即按照提供的间隔时间周期执行,一个周期内最多执行一次,如果设置该方法,则setMinimumLatency()
和setOverrideDeadline()
不可设置。
指定此作业应按提供的间隔和弹性重新执行。作业可以在周期结束时在具有flex长度的窗口中随时执行。
设置是否在设备重新启动时保持此作业,此方法需要RECEIVE_BOOT_COMPLETED
权限。
设置Job所需网络类型的详细描述,调用次方法后,将定义网络为该Job的严格要求,如果没有网络,那么该Job将不会执行。可以通过setOverrideDeadline()
来更改此行为。
当Job在
jobservice.onStartJob(jobParameters)
中执行时,请确保使用jobParameters.getNetwork()
返回的特定网络.
设置Job所需网络类型的基本描述;
可选参数在JobInfo中,如:JobInfo.NETWORK_TYPE_UNMETERED
指定该Job是否只在非低电量时运行,默认为false,如果指定为true,那么该job将仅仅在非低电量模式下运行。默认为false。
指定该Job是否只在充电时运行此Job。默认为false。
指定该Job是否只在DeviceIdle状态时运行此Job,即在交互状态时将不会运行。默认为false。
指定此Job是否只在可用存储空间太低时运行,默认为false。
设置临时附加项;
设置额外附加项,如果需要携带其他基本类型参数,可以通过这个方法设置。
创建JobInfo对象。
JobInfo中提供了几个用于方法参数的常量,以及和JobInfo.Builder中的setXXX()
方法对应的getXXX()
方法,此处就不再对这些方法进行说明,我们来看看它里面的一些常量的含义。
以指数形式重新调度job
以指数形式重新调度job
以上两常量作为JobInfo.Builder.setBackoffCriteria()
的第二个参数使用,指定重新调度Job的策略。
当重新执行一个job时,默认退让毫秒数(30s),JobInfo.Builder.setBackoffCriteria()
的第一个参数.
当重新执行一个job时,最大退让(延迟)毫秒数。
设置该值时,表示对应Job需要网络连接
设置该值时,表示对应Job需要网络连接,且为蜂窝网络
默认值,表示该Job对网络连接无要求
设置该值时,表示对应Job需要网络连接,且为非漫游网络
设置该值时,表示对应Job需要网络连接,且为WIFI(非计量)
以上这些NETWORK_TYPE_XXX
值,作为方法JobInfo.Builder.setRequiredNetworkType()
的参数使用,用于指定一个Job是否需要特殊网络条件。
在上面已经说过了,JobScheduler是一个系统服务,通过如下方式获取其实例:
Context.getSystemService(Context.JOB_SCHEDULER_SERVICE).
取消指定的Job,并将忽略JobService.onStopJob()
的返回值。
取消该应用已调度的所有的Job。
int enqueue (JobInfo job, JobWorkItem work)
List getAllPendingJobs ()
获取应用程序已调度的所有Job。
查找指定Job的描述信息。
开始调度一个Job,将使用JobInfo替换相同JobID中的所有信息,如果该Job正在运行,将会停止它。该方法返回值为RESULT_FAILURE
or RESULT_SUCCESS
,表示调度成功或失败。
在调用schedule()
时,提供参数无效时将返回该值。
在调用schedule()时,如果成功调度将返回该值。
JobService是JobScheduler最终回调的端点,JobScheduler将会回调该类中的onStartJob()
开始执行异步任务。该类是一个抽象类,用户必须继承JobScheduler实现一个类,并在配置文件中授予权限:
<service android:name="MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE" >
...
当Job开始执行时,将回调该方法,因此该方法中为所执行的内容,该方法执行在应用主线程中。当该方法执行完毕后,如果返回true,那么也就意味着Job将一直处于激活的状态,依旧持有WakeLock锁;如果返回false表示该Job完成后,将不会再继续进行,释放WakeLock锁。
如果返回true,有如下三种方式结束该Job的执行:
1.调用JobFinished()
方法通知系统已经完成其工作;
2.调用cancel()
方法取消该Job,此时将回调onStopJob()
方法;
3.如果没有任何处理,JobSchedulerService中将在600s后回调onStopJob()
方法,并在8s后结束该Job的执行。
因此,如果onStartJob()
执行完毕后,不再需要重复执行,则返回值更推荐使用false,当执行完毕任务后,将立即释放WakeLock锁,从而更好地优化功耗。
如果在调用前JobFinished()
系统停止该Job,则将回调该方法。比如在执行该Job过程中约束条件不满足导致停止了,这种情况下将回调该方法,然后将释放WakeLock锁。该方法返回true,则表示是否需要根据该Job创建时提供的重新执行策略重新调度该Job。返回false,则表示该job完全停止。
params
:job所携带的参数
wantsReschedule
:是否需要重复执行
该方法需要用户手动调用,以通知作业调度器已经完成该Job工作,系统收到调用信息后,将释放执行外Job时的WakeLock锁。
参数
wantsReschedule
如果设置为true,将根据setBackbackOffCriteria()
设置的执行策略进行调整。这种情况下,当重新调度作业时,最初的初始需求将被保留。
用来配置Job的参数容器,也就是说JobParamters有该Job的所有配置参数,因此它提供了多个getXXX()
方法可以获取这些参数。JobParamters参数无需用户自行创建,系统将会创建完成,并作为JobService中回调函数的参数。
在JobService的
onStartJob(JobParamters)
和onStopJob(JobParamters)
中,JobParamters做为参数使用。
Github:https://github.com/jeraon/jobscheduler
Google官方Sample:https://github.com/googlesamples/android-JobScheduler/#readme