1、先来说说SystemJobScheduler
api>=23使用,持有JobScheduler(5.0引入),由系统底层支持的调度服务,单个进程分配10个调度任务。
如下Configuration.java类计算最大可调度次数,api=23最大可调度25个,api>23可调度50个,所以一般来说足够了。所以api>=23大多数情况应该就是使用SystemJobScheduler。
// 如下代码计算最大的可调度个数
// int MAX_SCHEDULER_LIMIT = 50;
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@IntRange(from = Configuration.MIN_SCHEDULER_LIMIT, to = Scheduler.MAX_SCHEDULER_LIMIT)
public int getMaxSchedulerLimit() {
// We double schedule jobs in SDK 23. So use half the number of max slots specified.
if (Build.VERSION.SDK_INT == 23) {
return mMaxSchedulerLimit / 2;
} else {
return mMaxSchedulerLimit;
}
}
见SystemJobScheduler指定hasLimitedShedulingSlots=true。
//见SystemJobScheduler实现的Scheduler的如下接口
@Override
public boolean hasLimitedSchedulingSlots() {
return true;
}
下面是Schedulers.java中schedule()方法的部分代码,看出控制了在限度范围内的workSpec才会被 hasLimitedShcedulingSlots=true的调度器调度。
public static void schedule(
@NonNull Configuration configuration,
@NonNull WorkDatabase workDatabase,
List<Scheduler> schedulers) {
//此处省略部分无关代码
// Enqueued workSpecs when scheduling limits are applicable.
eligibleWorkSpecsForLimitedSlots = workSpecDao.getEligibleWorkForScheduling(
configuration.getMaxSchedulerLimit());
// 此处省略部分无关代码
if (eligibleWorkSpecsForLimitedSlots != null
&& eligibleWorkSpecsForLimitedSlots.size() > 0) {
WorkSpec[] eligibleWorkSpecsArray =
new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
eligibleWorkSpecsArray =
eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);
// Delegate to the underlying schedulers.
for (Scheduler scheduler : schedulers) {
if (scheduler.hasLimitedSchedulingSlots()) {
scheduler.schedule(eligibleWorkSpecsArray);
}
}
}
如果满足条件的Worker超过计算的调度槽数,就会交给hasLimitedShcedulingSlots=false的调度器,实际上就是GreedyScheduler见如下代码块
if (allEligibleWorkSpecs != null && allEligibleWorkSpecs.size() > 0) {
WorkSpec[] enqueuedWorkSpecsArray = new WorkSpec[allEligibleWorkSpecs.size()];
enqueuedWorkSpecsArray = allEligibleWorkSpecs.toArray(enqueuedWorkSpecsArray);
// Delegate to the underlying schedulers.
for (Scheduler scheduler : schedulers) {
if (!scheduler.hasLimitedSchedulingSlots()) {
scheduler.schedule(enqueuedWorkSpecsArray);
}
}
}
下面是最终调度代码,使用持有的JobScheduler实例
/**
* Schedules one job with JobScheduler.
*
* @param workSpec The {@link WorkSpec} to schedule with JobScheduler.
*/
@VisibleForTesting
public void scheduleInternal(WorkSpec workSpec, int jobId) {
JobInfo jobInfo = mSystemJobInfoConverter.convert(workSpec, jobId);
Logger.get().debug(
TAG,
String.format("Scheduling work ID %s Job ID %s", workSpec.id, jobId));
try {
int result = mJobScheduler.schedule(jobInfo);
接下来JobScheduler在引爆之后会交给SystemJobService的startJob()方法如下代码
@Override
public boolean onStartJob(@NonNull JobParameters params) {
// 省略一大段代码
// For more information look at b/123211993
mWorkManagerImpl.startWork(workSpecId, runtimeExtras);
return true;
}
2、再来说说SystemAlarmScheduler:
api<23使用,和SystemJobScheduler一样都是系统级的调度服务,也是单进程限制个数的调度任务,顾名思义就是使用AlarmService进行定时调度。跟SystemJobSchedule是相互替代作用,作用也一致。调度器引爆后会交给SystemAlarmService
3、最后说说GreedyScheduler:
当调度的workSpec超出系统提供的两类Scheduler的槽数限制时,就会使用GreedyScheduler来调度,当然也是有大小限制的见如下代码
/**
* The maximum number of {@link WorkSpec}s that are considered for execution by the greedy
* scheduler.
*/
int MAX_GREEDY_SCHEDULER_LIMIT = 200;
下面是schedule()方法中的关键行,延迟调度和立即执行。延迟调度最终使用的就是Handler
mHandler.postDelayed(runnable, delayInMillis);
@Override
public void schedule(@NonNull WorkSpec... workSpecs) {
//此处省略部分代码
if (now < nextRunTime) {
// Future work
if (mDelayedWorkTracker != null) {
mDelayedWorkTracker.schedule(workSpec);
}
}
// 此处省略部分代码
mWorkManagerImpl.startWork(workSpec.id);
}
立即执行部分,使用的是WorkManagerImpl初始化时创建的线程池来执行runnable
public void startWork(
@NonNull String workSpecId,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkTaskExecutor
.executeOnBackgroundThread(
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
综上是目前看到的部分,还有一些还没看完