先看其构造方法,它会将我们传递进来的WorkManagerImpl 与context进行保存,并在它的重载方法里获取了系统服务jobScheduler,要了解jobScheduler,推荐一篇博文可以看看JobScheduler的使用,
而另外一个参数SystemJobInfoConverter 则是用来将我们的workSpecs转化为JobInfo,这个JobInfo是jobScheduler需要的参数 ,用来描述任务的执行时间,条件,策略等一系列的行为。因为我们的workSpecs中包含worker执行的一些配置和条件,从而可以通过SystemJobInfoConverter将workSpecs转化为JobInfo
public SystemJobScheduler(@NonNull Context context, @NonNull WorkManagerImpl workManager) {
this(context,
workManager,
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE), //获取到了系统服务JobScheduler进行重载
new SystemJobInfoConverter(context)); //用来将我们传递的数据转换为JobInfo类型
}
@VisibleForTesting
public SystemJobScheduler(
Context context,
WorkManagerImpl workManager,
JobScheduler jobScheduler,
SystemJobInfoConverter systemJobInfoConverter) {
mWorkManager = workManager;
mJobScheduler = jobScheduler;
mIdGenerator = new IdGenerator(context);
mSystemJobInfoConverter = systemJobInfoConverter;
}
它的schedule方法,主要做了这么几件事,根据传递进来的WorkSpec的ID,从数据库获取对应的WorkSpec,并根据WorkSpec.id从SystemIdInfo这张数据表中获取对应的系统编号,该编号的一大作用是,在 调度器执行该worker时,消除重复的任务调用。
public void schedule(WorkSpec... workSpecs) {
WorkDatabase workDatabase = mWorkManager.getWorkDatabase();
for (WorkSpec workSpec : workSpecs) { //循环遍历workSpecs
workDatabase.beginTransaction();
try {
WorkSpec currentDbWorkSpec = workDatabase.workSpecDao().getWorkSpec(workSpec.id); //从数据库中根据id获取对应的WorkSpec
if (currentDbWorkSpec == null) {
Logger.get().warning(
TAG,
"Skipping scheduling " + workSpec.id
+ " because it's no longer in the DB");
continue;
} else if (currentDbWorkSpec.state != WorkInfo.State.ENQUEUED) {
Logger.get().warning(
TAG,
"Skipping scheduling " + workSpec.id
+ " because it is no longer enqueued");
continue;
}
SystemIdInfo info = workDatabase.systemIdInfoDao()
.getSystemIdInfo(workSpec.id); //获取对应的系统编号
if (info != null) {
JobInfo jobInfo = getPendingJobInfo(mJobScheduler, workSpec.id); //如果该workSpec 已经被转化为JobInfo 且已经放入到了jobScheduler,这直接跳过本次循环
if (jobInfo != null) {
Logger.get().debug(TAG, String.format(
"Skipping scheduling %s because JobScheduler is aware of it "
+ "already.",
workSpec.id));
continue;
}
}
int jobId = info != null ? info.systemId : mIdGenerator.nextJobSchedulerIdWithRange(
mWorkManager.getConfiguration().getMinJobSchedulerId(),
mWorkManager.getConfiguration().getMaxJobSchedulerId()); //将info.systemId作为jobId 如果为空,则根据Configuration中指定的条件去生成jobId
if (info == null) {
SystemIdInfo newSystemIdInfo = new SystemIdInfo(workSpec.id, jobId);
mWorkManager.getWorkDatabase()
.systemIdInfoDao()
.insertSystemIdInfo(newSystemIdInfo);
} //如果info为空,通过jobId与workSpec.id生成一条心的数据插入SystemIdInfo
scheduleInternal(workSpec, jobId);
if (Build.VERSION.SDK_INT == 23) {
int nextJobId = mIdGenerator.nextJobSchedulerIdWithRange(
mWorkManager.getConfiguration().getMinJobSchedulerId(),
mWorkManager.getConfiguration().getMaxJobSchedulerId());
scheduleInternal(workSpec, nextJobId); //根据条件调用scheduleInternal方法
}
workDatabase.setTransactionSuccessful();
} finally {
workDatabase.endTransaction();
}
}
}
查看scheduleInternal,在其内部,就是通过给定的参数,将workspec转化为jobinfo,并放入到JobScheduler中。JobScheduler是系统服务,由android程序启动的时候自动拉起无需手动去操作,而与JobScheduler对应的jobservice由系统自动生成,继续反编译查看apk
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));
mJobScheduler.schedule(jobInfo);
}
会发现系统为我们自动实现了一个SystemJobService,也就是当JobScheduler中的条件满足时,SystemJobService就会被调用到
在 SystemJobService中的onStartJob中,重点是最后一个方法,该方法调用了WorkManagerImpl.startWork,并将workSpecId,与runtimeExtras作为参数传入。
@Override
public boolean onStartJob(JobParameters params) {
//屏蔽了无关代码
mWorkManagerImpl.startWork(workSpecId, runtimeExtras);
return true;
}
在startWork中,调用了mWorkTaskExecutor去执行StartWorkRunnable
public void startWork(String workSpecId, WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkTaskExecutor
.executeOnBackgroundThread(
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
进入StartWorkRunnable的run方法中,调用了Processor的startWork方法(Processor之前有讲解)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class StartWorkRunnable implements Runnable {
private WorkManagerImpl mWorkManagerImpl;
private String mWorkSpecId;
private WorkerParameters.RuntimeExtras mRuntimeExtras;
public StartWorkRunnable(
WorkManagerImpl workManagerImpl,
String workSpecId,
WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkManagerImpl = workManagerImpl;
mWorkSpecId = workSpecId;
mRuntimeExtras = runtimeExtras;
}
@Override
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}
}
这里最终调用了mWorkManagerImpl.getProcessor().startWork方法
mWorkManagerImpl.getProcessor().startWork方法流程分析(该方法过程的调用会在后面多次使用到
)
Processor会在我们实例化WorkManagerImpl时构造,在Processor的startWork方法内首先会通过之前传递进来的对象锁进行加锁,然后在内部构件了一个workWrapper,它是一个runable,最后放到了mWorkTaskExecutor在后台去执行
public boolean startWork(String id, WorkerParameters.RuntimeExtras runtimeExtras) {
WorkerWrapper workWrapper;
synchronized (mLock) {
// Work may get triggered multiple times if they have passing constraints
// and new work with those constraints are added.
if (mEnqueuedWorkMap.containsKey(id)) {
Logger.get().debug(
TAG,
String.format("Work %s is already enqueued for processing", id));
return false;
}
workWrapper =
new WorkerWrapper.Builder(
mAppContext,
mConfiguration,
mWorkTaskExecutor,
mWorkDatabase,
id)
.withSchedulers(mSchedulers)
.withRuntimeExtras(runtimeExtras)
.build();
ListenableFuture future = workWrapper.getFuture();
future.addListener(
new FutureListener(this, id, future),
mWorkTaskExecutor.getMainThreadExecutor());
mEnqueuedWorkMap.put(id, workWrapper);
}
mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper);
Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id));
return true;
}
它的run方法内部比较复杂,主要是调用mWorker.startWork(),以及在最后结尾调用了onWorkFinished,接下来一个个分析这2步都做了什么动作
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId); //从WorkTag中获取到WorkSpecId对应的Tag
mWorkDescription = createWorkDescription(mTags); //创建work说明,内部通过StringBuilder进行拼接
runWorker();
}
private void runWorker() {
if (tryCheckForInterruptionAndResolve()) { //检查程序是否中断,如果中断直接返回
return;
}
mWorkDatabase.beginTransaction(); //开启数据库事务
try {
mWorkSpec = mWorkSpecDao.getWorkSpec(mWorkSpecId); //通过传递进来的WorkSpecId查询符合条件的WorkSpec并返回
if (mWorkSpec == null) { //如果没有找到打印错误直接返回
Logger.get().error(
TAG,
String.format("Didn't find WorkSpec for id %s", mWorkSpecId));
resolve(false);
return;
}
// Do a quick check to make sure we don't need to bail out in case this work is already
// running, finished, or is blocked.
if (mWorkSpec.state != ENQUEUED) { //如果该WorkSpec的状态不为ENQUEUED,表示对应的worker没有入队,无事可做,直接返回
resolveIncorrectStatus(); //继续检查WorkSpec的状态是否为running,如果是,则重新安排
mWorkDatabase.setTransactionSuccessful(); //设置数据库中对应状态为successful
Logger.get().debug(TAG,
String.format("%s is not in ENQUEUED state. Nothing more to do.",
mWorkSpec.workerClassName));
return;
}
if (mWorkSpec.isPeriodic() || mWorkSpec.isBackedOff()) {
long now = System.currentTimeMillis();
// Allow first run of a PeriodicWorkRequest when flex is applicable
// (when using AlarmManager) to go through. This is because when periodStartTime=0;
// calculateNextRunTime() always > now. We are being overly cautious with the
// SDK_INT check and the intervalDuration != flexDuration check.
// For more information refer to b/124274584
boolean isFirstRunWhenFlexApplicable =
Build.VERSION.SDK_INT < WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL
&& mWorkSpec.intervalDuration != mWorkSpec.flexDuration
&& mWorkSpec.periodStartTime == 0;
if (!isFirstRunWhenFlexApplicable && now < mWorkSpec.calculateNextRunTime()) {
Logger.get().debug(TAG,
String.format(
"Delaying execution for %s because it is being executed "
+ "before schedule.",
mWorkSpec.workerClassName));
// For AlarmManager implementation we need to reschedule this kind of Work.
// This is not a problem for JobScheduler because we will only reschedule
// work if JobScheduler is unaware of a jobId.
resolve(true);
return;
}
}
// Needed for nested transactions, such as when we're in a dependent work request when
// using a SynchronousExecutor.
mWorkDatabase.setTransactionSuccessful();
} finally {
mWorkDatabase.endTransaction();
}
// Merge inputs. This can be potentially expensive code, so this should not be done inside
// a database transaction.
Data input;
if (mWorkSpec.isPeriodic()) { //判断是否是定期任务
input = mWorkSpec.input; //将我们通过workRequest传入的参数保存
} else {
InputMerger inputMerger = InputMerger.fromClassName(mWorkSpec.inputMergerClassName); //通过WorkSpec中存储的worker的类名反射构造该worker的实例
if (inputMerger == null) {
Logger.get().error(TAG, String.format("Could not create Input Merger %s",
mWorkSpec.inputMergerClassName));
setFailedAndResolve();
return;
}
List inputs = new ArrayList<>();
inputs.add(mWorkSpec.input);
inputs.addAll(mWorkSpecDao.getInputsFromPrerequisites(mWorkSpecId));
input = inputMerger.merge(inputs); //将我们执行worker的入参添加到input中去
}
WorkerParameters params = new WorkerParameters(
UUID.fromString(mWorkSpecId),
input,
mTags,
mRuntimeExtras,
mWorkSpec.runAttemptCount,
mConfiguration.getExecutor(),
mWorkTaskExecutor,
mConfiguration.getWorkerFactory());
// Not always creating a worker here, as the WorkerWrapper.Builder can set a worker override
// in test mode.
if (mWorker == null) { //如果mWorker 为空,则根据WorkSpec.workerClassName创建一个worker实例
mWorker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
mAppContext,
mWorkSpec.workerClassName,
params);
}
if (mWorker == null) {
Logger.get().error(TAG,
String.format("Could not create Worker %s", mWorkSpec.workerClassName));
setFailedAndResolve();
return;
}
if (mWorker.isUsed()) { //如果该mWorker已经被调用过
Logger.get().error(TAG,
String.format("Received an already-used Worker %s; WorkerFactory should return "
+ "new instances",
mWorkSpec.workerClassName));
setFailedAndResolve();
return;
}
mWorker.setUsed(); //将mWorker设置为已被使用
// Try to set the work to the running state. Note that this may fail because another thread
// may have modified the DB since we checked last at the top of this function.
if (trySetRunning()) { //尝试运行
if (tryCheckForInterruptionAndResolve()) { //检查任务是否中断并尝试解决
return;
}
final SettableFuture future = SettableFuture.create(); //构造一个future 实例
// Call mWorker.startWork() on the main thread.
mWorkTaskExecutor.getMainThreadExecutor() //切换到主线程执行任务
.execute(new Runnable() {
@Override
public void run() {
try {
Logger.get().debug(TAG, String.format("Starting work for %s",
mWorkSpec.workerClassName));
mInnerFuture = mWorker.startWork(); //调用了worker实例的startwork方法并将执行结果返回
future.setFuture(mInnerFuture); //将结果放入future
} catch (Throwable e) {
future.setException(e);
}
}
});
// Avoid synthetic accessors.
final String workDescription = mWorkDescription;
future.addListener(new Runnable() { //future监听通知,
@Override
@SuppressLint("SyntheticAccessor")
public void run() {
try {
// If the ListenableWorker returns a null result treat it as a failure.
ListenableWorker.Result result = future.get(); //将上面通过setFuture获得的结果返回
if (result == null) {
Logger.get().error(TAG, String.format(
"%s returned a null result. Treating it as a failure.",
mWorkSpec.workerClassName));
} else {
Logger.get().debug(TAG, String.format("%s returned a %s result.",
mWorkSpec.workerClassName, result));
mResult = result; //将结果赋值给mResult
}
} catch (CancellationException exception) {
// Cancellations need to be treated with care here because innerFuture
// cancellations will bubble up, and we need to gracefully handle that.
Logger.get().info(TAG, String.format("%s was cancelled", workDescription),
exception);
} catch (InterruptedException | ExecutionException exception) {
Logger.get().error(TAG,
String.format("%s failed because it threw an exception/error",
workDescription), exception);
} finally {
onWorkFinished(); //
}
}
}, mWorkTaskExecutor.getBackgroundExecutor());
} else {
resolveIncorrectStatus();
}
}
首先看startWork方法,它是ListenableWorker中的方法,而ListenableWorker是Worker的父类,查看Worker,在它的startWork
中开启了一个线程池去执行dowork方法,到这一步,终于走完了整个调用过程,也就是我们创建的继承Worker类的testworker中的dowork方法会被调用,完成了后台任务的执行。当我们的dowork执行完毕后,会返回该结果,而这个结果在上面说了,是通过result进行了接收。而该状态会在onWorkFinished方法中进行更新。SystemJobScheduler的执行流程分析完毕。
public final @NonNull ListenableFuture startWork() {
mFuture = SettableFuture.create();
getBackgroundExecutor().execute(new Runnable() {
@Override
public void run() {
try {
Result result = doWork();
mFuture.set(result);
} catch (Throwable throwable) {
mFuture.setException(throwable);
}
}
});
return mFuture;
}
**
**
进入SystemAlarmScheduler的schedule方法,它会对传入的workSpecs进行遍历,并调用scheduleWorkSpec方法
public void schedule(WorkSpec... workSpecs) {
for (WorkSpec workSpec : workSpecs) {
scheduleWorkSpec(workSpec);
}
}
而这个方法会调用createScheduleWorkIntent创建SystemAlarmService服务并将我们的workspecid进行传入,并开启该服务
private void scheduleWorkSpec(@NonNull WorkSpec workSpec) {
Logger.get().debug(TAG, String.format("Scheduling work with workSpecId %s", workSpec.id));
Intent scheduleIntent = CommandHandler.createScheduleWorkIntent(mContext, workSpec.id);
mContext.startService(scheduleIntent);
}
static Intent createScheduleWorkIntent(@NonNull Context context, @NonNull String workSpecId) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_SCHEDULE_WORK);
intent.putExtra(KEY_WORKSPEC_ID, workSpecId);
return intent;
}
除此之外,还可以通过反编译apk看出,系统自动为我们静态注册了很多系统广播,
当我们接收到这些系统广播时,就会调用到createConstraintsChangedIntent,拉起SystemAlarmService,也就是当接收到这些广播时,SystemAlarmService会被拉起,然后根据传入的intent进行一系列操作,从而执行符合条件的worker
abstract class ConstraintProxy extends BroadcastReceiver {
private static final String TAG = Logger.tagWithPrefix("ConstraintProxy");
@Override
public void onReceive(Context context, Intent intent) {
Logger.get().debug(TAG, String.format("onReceive : %s", intent));
Intent constraintChangedIntent = CommandHandler.createConstraintsChangedIntent(context);
context.startService(constraintChangedIntent);
}
/**
* Proxy for Battery Not Low constraint
*/
public static class BatteryNotLowProxy extends ConstraintProxy {
}
/**
* Proxy for Battery Charging constraint
*/
public static class BatteryChargingProxy extends ConstraintProxy {
}
/**
* Proxy for Storage Not Low constraint
*/
public static class StorageNotLowProxy extends ConstraintProxy {
}
/**
* Proxy for Network State constraints
*/
public static class NetworkStateProxy extends ConstraintProxy {
}
查看该服务做了些什么,发现其内部创建了SystemAlarmDispatcher对象,并在onStartCommand中调用了其add方法
public class SystemAlarmService extends LifecycleService
implements SystemAlarmDispatcher.CommandsCompletedListener {
private static final String TAG = Logger.tagWithPrefix("SystemAlarmService");
private SystemAlarmDispatcher mDispatcher;
@Override
public void onCreate() {
super.onCreate();
mDispatcher = new SystemAlarmDispatcher(this);
mDispatcher.setCompletedListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
mDispatcher.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (intent != null) {
mDispatcher.add(intent, startId); //在这里进行了调用
}
// If the service were to crash, we want all unacknowledged Intents to get redelivered.
return Service.START_REDELIVER_INTENT;
}
@MainThread
@Override
public void onAllCommandsCompleted() {
Logger.get().debug(TAG, "All commands completed in dispatcher");
// Check to see if we hold any more wake locks.
WakeLocks.checkWakeLocks();
// No need to pass in startId; stopSelf() translates to stopSelf(-1) which is a hard stop
// of all startCommands. This is the behavior we want.
stopSelf();
}
}
在该add方法中,会将我们传递进来的intent放入到mIntents中去,该mIntents是一个intent的list集合,并在最后调用了processCommand方法
public boolean add(@NonNull final Intent intent, final int startId) {
Logger.get().debug(TAG, String.format("Adding command %s (%s)", intent, startId));
assertMainThread(); //必须在主线程调用
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
Logger.get().warning(TAG, "Unknown command. Ignoring");
return false;
}
// If we have a constraints changed intent in the queue don't add a second one. We are
// treating this intent as special because every time a worker with constraints is complete
// it kicks off an update for constraint proxies.
if (CommandHandler.ACTION_CONSTRAINTS_CHANGED.equals(action)
&& hasIntentWithAction(CommandHandler.ACTION_CONSTRAINTS_CHANGED)) {
return false;
}
intent.putExtra(KEY_START_ID, startId);
synchronized (mIntents) {
boolean hasCommands = !mIntents.isEmpty();
mIntents.add(intent); //将intent放入到集合中去
if (!hasCommands) {
// Only call processCommand if this is the first command.
// The call to dequeueAndCheckForCompletion will process the remaining commands
// in the order that they were added.
processCommand();
}
}
return true;
}
该方法内会将我们的intent传递给mCommandHandler.onHandleIntent去处理
private void processCommand() {
assertMainThread(); //确保在主线程执行
PowerManager.WakeLock processCommandLock = //
WakeLocks.newWakeLock(mContext, PROCESS_COMMAND_TAG);
try {
processCommandLock.acquire(); //获取锁
// Process commands on the background thread.
mWorkManager.getWorkTaskExecutor().executeOnBackgroundThread(new Runnable() { //将任务切换到WorkManager中的WorkTaskExecutor去执行
@Override
public void run() {
synchronized (mIntents) { //对mIntents加锁
mCurrentIntent = mIntents.get(0); //从mIntents中获取intent
}
if (mCurrentIntent != null) {
final String action = mCurrentIntent.getAction();
final int startId = mCurrentIntent.getIntExtra(KEY_START_ID,
DEFAULT_START_ID);
Logger.get().debug(TAG,
String.format("Processing command %s, %s", mCurrentIntent,
startId));
final PowerManager.WakeLock wakeLock = WakeLocks.newWakeLock(
mContext,
String.format("%s (%s)", action, startId));
try {
Logger.get().debug(TAG, String.format(
"Acquiring operation wake lock (%s) %s",
action,
wakeLock));
wakeLock.acquire();
mCommandHandler.onHandleIntent(mCurrentIntent, startId,
SystemAlarmDispatcher.this); //调用mCommandHandler.onHandleIntent方法
} catch (Throwable throwable) {
Logger.get().error(
TAG,
"Unexpected error in onHandleIntent",
throwable);
} finally {
Logger.get().debug(
TAG,
String.format(
"Releasing operation wake lock (%s) %s",
action,
wakeLock));
wakeLock.release(); //释放锁
// Check if we have processed all commands
postOnMainThread(
new DequeueAndCheckForCompletion(SystemAlarmDispatcher.this)); // 当执行完毕后在主线程将本次任务意图从intents中进行移除
}
}
}
});
} finally {
processCommandLock.release();
}
}
这个方法内使用到了状态模式,会对intent的action进行判断,并做不同的处理,当我们第一次进入时会进入handleScheduleWorkIntent
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
String action = intent.getAction();
if (ACTION_CONSTRAINTS_CHANGED.equals(action)) {
handleConstraintsChanged(intent, startId, dispatcher); //如果约束发生了改变啊,则更新数据库中workspec的状态,并重新构建intent重新添加到intents集合中去
} else if (ACTION_RESCHEDULE.equals(action)) { //如果执行的时间发生变化
handleReschedule(intent, startId, dispatcher);
} else {
Bundle extras = intent.getExtras();
if (!hasKeys(extras, KEY_WORKSPEC_ID)) {
Logger.get().error(TAG,
String.format("Invalid request for %s, requires %s.",
action,
KEY_WORKSPEC_ID));
} else { //对intent的action进行判断,并做不同的处理,当我们第一次开启service时,action为ACTION_SCHEDULE_WORK
if (ACTION_SCHEDULE_WORK.equals(action)) {
handleScheduleWorkIntent(intent, startId, dispatcher); //处理任务
} else if (ACTION_DELAY_MET.equals(action)) {
handleDelayMet(intent, startId, dispatcher); //处理延迟
} else if (ACTION_STOP_WORK.equals(action)) {
handleStopWork(intent, startId, dispatcher); //处理任务停止
} else if (ACTION_EXECUTION_COMPLETED.equals(action)) {
handleExecutionCompleted(intent, startId, dispatcher); //处理任务完成
} else {
Logger.get().warning(TAG, String.format("Ignoring intent %s", intent));
}
}
}
}
查看handleReschedule做了什么,该方法会调用WorkManagerImpl的rescheduleEligibleWork
private void handleReschedule(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
Logger.get().debug(TAG, String.format("Handling reschedule %s, %s", intent, startId));
dispatcher.getWorkManager().rescheduleEligibleWork();
}
在这个方法内会将我们的任务状态进行更新,并重新调用Schedulers.schedule
public void rescheduleEligibleWork() {
// TODO (rahulrav@) Make every scheduler do its own cancelAll().
if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
SystemJobScheduler.jobSchedulerCancelAll(getApplicationContext());
}
// Reset scheduled state.
getWorkDatabase().workSpecDao().resetScheduledState();
// Delegate to the WorkManager's schedulers.
// Using getters here so we can use from a mocked instance
// of WorkManagerImpl.
Schedulers.schedule(getConfiguration(), getWorkDatabase(), getSchedulers());
}
查看handleScheduleWorkIntent,这里会判断workSpec是否存在约束,最终会走到Alarms.setAlarm中去,区别在于如果存在约束,则会调用完Alarms.setAlarm之后通过CommandHandler.createConstraintsChangedIntent构建一个intent意图发送给Dispatcher,然后重新进行一次回调
private void handleScheduleWorkIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
if (!workSpec.hasConstraints()) { //该workspec是否存在约束
Logger.get().debug(TAG,
String.format("Setting up Alarms for %s at %s", workSpecId, triggerAt));
Alarms.setAlarm(mContext, dispatcher.getWorkManager(), workSpecId, triggerAt);
} else {
// Schedule an alarm irrespective of whether all constraints matched.
Logger.get().debug(TAG,
String.format("Opportunistically setting an alarm for %s at %s", workSpecId,
triggerAt));
Alarms.setAlarm(
mContext,
dispatcher.getWorkManager(),
workSpecId,
triggerAt);
Intent constraintsUpdate = CommandHandler.createConstraintsChangedIntent(mContext);
dispatcher.postOnMainThread(
new SystemAlarmDispatcher.AddRunnable( //在主线程调用了AddRunnable
dispatcher,
constraintsUpdate,
startId));
}
workDatabase.setTransactionSuccessful();
} finally {
workDatabase.endTransaction();
}
}
static Intent createConstraintsChangedIntent(@NonNull Context context) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_CONSTRAINTS_CHANGED); //约束发生了变更
return intent;
}
查看 该AddRunnable 的run方法,会重新调用dispatcher的add方法,此时的intent的action已经发生了变化,所以当再次走到onHandleIntent方法时,就会走不同的调用渠道。(状态模式)
static class AddRunnable implements Runnable {
private final SystemAlarmDispatcher mDispatcher;
private final Intent mIntent;
private final int mStartId;
AddRunnable(@NonNull SystemAlarmDispatcher dispatcher,
@NonNull Intent intent,
int startId) {
mDispatcher = dispatcher;
mIntent = intent;
mStartId = startId;
}
@Override
public void run() {
mDispatcher.add(mIntent, mStartId); //在这里将该intent作为参数,执行其add方法
}
}
继续查看setAlarm, 这个方法内,会通过数据库中根据workSpecId去获取对应的系统编号,如果没有则会获取一个系统编号,并注册到数据库中去,他们最终都调用了setExactAlarm方法
public static void setAlarm(
@NonNull Context context,
@NonNull WorkManagerImpl workManager,
@NonNull String workSpecId,
long triggerAtMillis) {
WorkDatabase workDatabase = workManager.getWorkDatabase();
SystemIdInfoDao systemIdInfoDao = workDatabase.systemIdInfoDao();
SystemIdInfo systemIdInfo = systemIdInfoDao.getSystemIdInfo(workSpecId); //获取workSpecId对应的系统编号
if (systemIdInfo != null) { //对systemIdInfo 进行判断并做不同处理
cancelExactAlarm(context, workSpecId, systemIdInfo.systemId);
setExactAlarm(context, workSpecId, systemIdInfo.systemId, triggerAtMillis);
} else {
IdGenerator idGenerator = new IdGenerator(context);
int alarmId = idGenerator.nextAlarmManagerId();
SystemIdInfo newSystemIdInfo = new SystemIdInfo(workSpecId, alarmId); //重新构建systemIdInfo 并放入数据库
systemIdInfoDao.insertSystemIdInfo(newSystemIdInfo);
setExactAlarm(context, workSpecId, alarmId, triggerAtMillis);
}
}
在这里会获取AlarmManager,它属于系统服务之一的定时服务,会根据指定的意图,在合适的时间去调用所对应的SystemAlarmService,在这里会通过CommandHandler.createDelayMetIntent去创建一个inent,并放入到了AlarmManager
该createDelayMetIntent创造的意图的action为ACTION_DELAY_MET
static Intent createDelayMetIntent(@NonNull Context context, @NonNull String workSpecId) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_DELAY_MET); //表明为延迟任务
intent.putExtra(KEY_WORKSPEC_ID, workSpecId);
return intent;
}
该定时服务会根据我们指定的PendingIntent,在合适的时间开启其对应的SystemAlarmService,并将对应的intent传递到SystemAlarmService中去,上面说过了在该SystemAlarmService的onStartCommand方法中调用了Dispatcher.add方法且将intent作为参数,这个方法最终又执行到了onHandleIntent方法,且此时的intent.action发生了变化,所以会走不同的渠道(状态模式)
private static void setExactAlarm(
@NonNull Context context,
@NonNull String workSpecId,
int alarmId,
long triggerAtMillis) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); //获取系统服务alarmManager
Intent delayMet = CommandHandler.createDelayMetIntent(context, workSpecId);
PendingIntent pendingIntent = PendingIntent.getService(
context, alarmId, delayMet, PendingIntent.FLAG_ONE_SHOT); //根据传递进来的intent构造pendingIntent
if (alarmManager != null) {
if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(RTC_WAKEUP, triggerAtMillis, pendingIntent);
} else {
alarmManager.set(RTC_WAKEUP, triggerAtMillis, pendingIntent);
}
}
}
通过反编译apk看出,该service由程序自动生成,无需手动实现
上面分析了,执行了setAlarm方法后,会重新构建一个intent并放入到了SystemAlarmService中,而该intent的action为ACTION_DELAY_MET,所以当再次执行到onHandleIntent时,就调用到了handleDelayMet方法
该方法主要执行了delayMetCommandHandler.handleProcessWork
private void handleDelayMet(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
Bundle extras = intent.getExtras();
synchronized (mLock) {
String workSpecId = extras.getString(KEY_WORKSPEC_ID); //通过KEY_WORKSPEC_ID获取workSpecId
Logger.get().debug(TAG, String.format("Handing delay met for %s", workSpecId));
// Check to see if we are already handling an ACTION_DELAY_MET for the WorkSpec.
// If we are, then there is nothing for us to do.
if (!mPendingDelayMet.containsKey(workSpecId)) { //如果不是延迟任务,则打印错误
DelayMetCommandHandler delayMetCommandHandler =
new DelayMetCommandHandler(mContext, startId, workSpecId,
dispatcher); //由DelayMetCommandHandler 进行一次封装
mPendingDelayMet.put(workSpecId, delayMetCommandHandler);
delayMetCommandHandler.handleProcessWork(); //执行handleProcessWork
} else {
Logger.get().debug(TAG,
String.format("WorkSpec %s is already being handled for ACTION_DELAY_MET",
workSpecId));
}
}
}
在handleProcessWork中,会根据是否有约束选择调用onAllConstraintsMet与mWorkConstraintsTracker.replace
void handleProcessWork() {
mWakeLock = WakeLocks.newWakeLock(
mContext,
String.format("%s (%s)", mWorkSpecId, mStartId));
Logger.get().debug(TAG,
String.format("Acquiring wakelock %s for WorkSpec %s", mWakeLock, mWorkSpecId));
mWakeLock.acquire(); //加锁
WorkSpec workSpec = mDispatcher.getWorkManager()
.getWorkDatabase()
.workSpecDao()
.getWorkSpec(mWorkSpecId); //根据mWorkSpecId获取workSpec
// This should typically never happen. Cancelling work should remove alarms, but if an
// alarm has already fired, then fire a stop work request to remove the pending delay met
// command handler.
if (workSpec == null) {
stopWork();
return;
}
// Keep track of whether the WorkSpec had constraints. This is useful for updating the
// state of constraint proxies when onExecuted().
mHasConstraints = workSpec.hasConstraints();
if (!mHasConstraints) { //判断是否有约束
Logger.get().debug(TAG, String.format("No constraints for %s", mWorkSpecId));
onAllConstraintsMet(Collections.singletonList(mWorkSpecId));
} else {
// Allow tracker to report constraint changes
mWorkConstraintsTracker.replace(Collections.singletonList(workSpec));
}
}
如果没有约束则在这个方法内,调用了Dispatcher.getProcessor().startWork(mWorkSpecId);最终完成了worker的执行 (上面有讲该执行的过程)
public void onAllConstraintsMet(@NonNull List workSpecIds) {
// WorkConstraintsTracker will call onAllConstraintsMet with list of workSpecs whose
// constraints are met. Ensure the workSpecId we are interested is part of the list
// before we call Processor#startWork().
if (!workSpecIds.contains(mWorkSpecId)) {
return;
}
Logger.get().debug(TAG, String.format("onAllConstraintsMet for %s", mWorkSpecId));
// Constraints met, schedule execution
// Not using WorkManagerImpl#startWork() here because we need to know if the processor
// actually enqueued the work here.
// TODO(rahulrav@) Once WorkManagerImpl provides a callback for acknowledging if
// work was enqueued, call WorkManagerImpl#startWork().
boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId); //在这里调用
if (isEnqueued) {
// setup timers to enforce quotas on workers that have
// been enqueued
mDispatcher.getWorkTimer()
.startTimer(mWorkSpecId, CommandHandler.WORK_PROCESSING_TIME_IN_MS, this);
} else {
// if we did not actually enqueue the work, it was enqueued before
// cleanUp and pretend this never happened.
cleanUp();
}
}
再查看其有约束的情况下怎么处理,
WorkConstraintsTracker.replace执行过程
查看WorkConstraintsTracker.replace方法,在这里调用了controller.replace(workSpecs);
public void replace(@NonNull List workSpecs) {
synchronized (mLock) {
for (ConstraintController controller : mConstraintControllers) {
controller.setCallback(null);
}
for (ConstraintController controller : mConstraintControllers) {
controller.replace(workSpecs);
}
for (ConstraintController controller : mConstraintControllers) {
controller.setCallback(this);
}
}
}
replace主要就是遍历 workSpecs,并将有约束的workSpec添加到mMatchingWorkSpecIds,并在最后调用了updateCallback
public void replace(@NonNull List workSpecs) {
mMatchingWorkSpecIds.clear();
for (WorkSpec workSpec : workSpecs) { //循环遍历workSpecs,判断其是否存在约束
if (hasConstraint(workSpec)) {
mMatchingWorkSpecIds.add(workSpec.id); //如果有则添加到mMatchingWorkSpecIds
}
}
if (mMatchingWorkSpecIds.isEmpty()) {
mTracker.removeListener(this);
} else {
mTracker.addListener(this);
}
updateCallback();
}
这里updateCallback会根据约束情况来选择调用,而看源码可以发现这里是个回调方法,由WorkConstraintsTracker进行了实现
private void updateCallback() {
if (mMatchingWorkSpecIds.isEmpty() || mCallback == null) {
return;
}
if (mCurrentValue == null || isConstrained(mCurrentValue)) { //此处通过mCurrentValue 进行判断
mCallback.onConstraintNotMet(mMatchingWorkSpecIds); //如果不存在约束,或者约束条件满足
} else {
mCallback.onConstraintMet(mMatchingWorkSpecIds); //存在约束的情况
}
}
@Override
public void onConstraintChanged(@Nullable T newValue) { //当约束发生改变时会调用这个方法,并对mCurrentValue 赋值
mCurrentValue = newValue;
updateCallback();
}
WorkConstraintsTracker的onConstraintMet主要是判断有约束条件的workSpecId的条件是否已经全部满足,如果满足则和不受约束的workSpecId做相同的处理,这里继续发生了回调
public void onConstraintMet(@NonNull List workSpecIds) {
synchronized (mLock) {
List unconstrainedWorkSpecIds = new ArrayList<>();
for (String workSpecId : workSpecIds) { //遍历查看workSpec是否所有约束都满足
if (areAllConstraintsMet(workSpecId)) {
Logger.get().debug(TAG, String.format("Constraints met for %s", workSpecId));
unconstrainedWorkSpecIds.add(workSpecId); //将满足所有条件的workSpecId 放入到该list中去
}
}
if (mCallback != null) {
mCallback.onAllConstraintsMet(unconstrainedWorkSpecIds); //在这里调用onAllConstraintsMet,与不受约束条件的workSpecId 走了相同的渠道
}
}
}
@Override
public void onConstraintNotMet(@NonNull List workSpecIds) {
synchronized (mLock) {
if (mCallback != null) {
mCallback.onAllConstraintsNotMet(workSpecIds);
}
}
}
具体的方法调用是在DelayMetCommandHandler中,最终又走到了onAllConstraintsMet
方法,完成了整体调用
public void onAllConstraintsMet(@NonNull List workSpecIds) {
// WorkConstraintsTracker will call onAllConstraintsMet with list of workSpecs whose
// constraints are met. Ensure the workSpecId we are interested is part of the list
// before we call Processor#startWork().
if (!workSpecIds.contains(mWorkSpecId)) {
return;
}
Logger.get().debug(TAG, String.format("onAllConstraintsMet for %s", mWorkSpecId));
// Constraints met, schedule execution
// Not using WorkManagerImpl#startWork() here because we need to know if the processor
// actually enqueued the work here.
// TODO(rahulrav@) Once WorkManagerImpl provides a callback for acknowledging if
// work was enqueued, call WorkManagerImpl#startWork().
boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId);
if (isEnqueued) {
// setup timers to enforce quotas on workers that have
// been enqueued
mDispatcher.getWorkTimer()
.startTimer(mWorkSpecId, CommandHandler.WORK_PROCESSING_TIME_IN_MS, this);
} else {
// if we did not actually enqueue the work, it was enqueued before
// cleanUp and pretend this never happened.
cleanUp();
}
}
到这里为止SystemAlarmScheduler的执行流程分析完毕
它的执行过程相比之下比较简单,如果worker(这里使用的是workspec,但其描述的是对应的worker,与该worker有关联关系,这里对workspec的判断,其实还是对worker执行条件的判断)不受约束,则直接调用WorkManagerImpl.startWork去执行worker,否则调用WorkConstraintsTracker.replace。
public void schedule(WorkSpec... workSpecs) {
registerExecutionListenerIfNeeded();
// Keep track of the list of new WorkSpecs whose constraints need to be tracked.
// Add them to the known list of constrained WorkSpecs and call replace() on
// WorkConstraintsTracker. That way we only need to synchronize on the part where we
// are updating mConstrainedWorkSpecs.
List constrainedWorkSpecs = new ArrayList<>();
List constrainedWorkSpecIds = new ArrayList<>();
for (WorkSpec workSpec: workSpecs) { //循环遍历workSpecs
if (workSpec.state == WorkInfo.State.ENQUEUED //是否入队
&& !workSpec.isPeriodic() //是否定期任务
&& workSpec.initialDelay == 0L //初始延迟是否为0
&& !workSpec.isBackedOff()) { //是否为回退状态
if (workSpec.hasConstraints()) { //是否存在约束
// Exclude content URI triggers - we don't know how to handle them here so the
// background scheduler should take care of them.
if (Build.VERSION.SDK_INT < 24
|| !workSpec.constraints.hasContentUriTriggers()) {
constrainedWorkSpecs.add(workSpec);
constrainedWorkSpecIds.add(workSpec.id); 将有约束的workSpec和workSpec.id分别进行保存
}
} else {
Logger.get().debug(TAG, String.format("Starting work for %s", workSpec.id));
mWorkManagerImpl.startWork(workSpec.id); //否则调用WorkManagerImpl.startWork进行执行
}
}
}
// onExecuted() which is called on the main thread also modifies the list of mConstrained
// WorkSpecs. Therefore we need to lock here.
synchronized (mLock) {
if (!constrainedWorkSpecs.isEmpty()) { //如果constrainedWorkSpecs不为空,也就是还有受限的WorkSpec存在时进入
Logger.get().debug(TAG, String.format("Starting tracking for [%s]",
TextUtils.join(",", constrainedWorkSpecIds)));
mConstrainedWorkSpecs.addAll(constrainedWorkSpecs);
mWorkConstraintsTracker.replace(mConstrainedWorkSpecs);
}
}
}
WorkConstraintsTracker.replace,这个方法之前已经分析过了,不过在GreedyScheduler中,我们最后一步步回调会调用到GreedyScheduler
public void replace(@NonNull List workSpecs) {
synchronized (mLock) {
for (ConstraintController controller : mConstraintControllers) {
controller.setCallback(null);
}
for (ConstraintController controller : mConstraintControllers) {
controller.replace(workSpecs);
}
for (ConstraintController controller : mConstraintControllers) {
controller.setCallback(this);
}
}
}
可以发现在这2个方法中,对于符合条件和不符合条件的worker,循环遍历去执行或者做停止操作
@Override
public void onAllConstraintsMet(@NonNull List workSpecIds) {
for (String workSpecId : workSpecIds) {
Logger.get().debug(
TAG,
String.format("Constraints met: Scheduling work ID %s", workSpecId));
mWorkManagerImpl.startWork(workSpecId); //调用了 mWorkManagerImpl.startWork方法
}
}
@Override
public void onAllConstraintsNotMet(@NonNull List workSpecIds) {
for (String workSpecId : workSpecIds) {
Logger.get().debug(TAG,
String.format("Constraints not met: Cancelling work ID %s", workSpecId));
mWorkManagerImpl.stopWork(workSpecId); //调用 mWorkManagerImpl.stopWork方法
}
}
查看WorkManagerImpl.startWork方法
public void startWork(String workSpecId, WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkTaskExecutor
.executeOnBackgroundThread(
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
发现最终也是调用了Processor().startWork
public class StartWorkRunnable implements Runnable {
private WorkManagerImpl mWorkManagerImpl;
private String mWorkSpecId;
private WorkerParameters.RuntimeExtras mRuntimeExtras;
public StartWorkRunnable(
WorkManagerImpl workManagerImpl,
String workSpecId,
WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkManagerImpl = workManagerImpl;
mWorkSpecId = workSpecId;
mRuntimeExtras = runtimeExtras;
}
@Override
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras); //在这里执行
}
}
到此为止,3大调度器的工作流程和原理全部分析完毕