先看其构造方法,它会将我们传递进来的WorkManagerImpl 与context进行保存,并在它的重载方法里获取了系统服务jobScheduler,要了解jobScheduler,推荐一篇博文可以看看JobScheduler的使用, 而另外一个参数SystemJobInfoConverter 则是用来将我们的workSpecs转化为JobInfo,这个JobInfo是jobScheduler需要的参数 ,用来描述任务的执行时间,条件,策略等一系列的行为。因为我们的workSpecs中包含worker执行的一些配置和条件,从而可以通过SystemJobInfoConverter将workSpecs转化为JobInfo 它的schedule方法,主要做了这么几件事,根据传递进来的WorkSpec的ID,从数据库获取对应的WorkSpec,并根据WorkSpec.id从SystemIdInfo这张数据表中获取对应的系统编号,该编号的一大作用是,在 调度器执行该worker时,消除重复的任务调用。 查看scheduleInternal,在其内部,就是通过给定的参数,将workspec转化为jobinfo,并放入到JobScheduler中。JobScheduler是系统服务,由android程序启动的时候自动拉起无需手动去操作,而与JobScheduler对应的jobservice由系统自动生成,继续反编译查看apk 会发现系统为我们自动实现了一个SystemJobService,也就是当JobScheduler中的条件满足时,SystemJobService就会被调用到 在 SystemJobService中的onStartJob中,重点是最后一个方法,该方法调用了WorkManagerImpl.startWork,并将workSpecId,与runtimeExtras作为参数传入。 进入StartWorkRunnable的run方法中,调用了Processor的startWork方法(Processor之前有讲解) 这里最终调用了mWorkManagerImpl.getProcessor().startWork方法 mWorkManagerImpl.getProcessor().startWork方法流程分析( Processor会在我们实例化WorkManagerImpl时构造,在Processor的startWork方法内首先会通过之前传递进来的对象锁进行加锁,然后在内部构件了一个workWrapper,它是一个runable,最后放到了mWorkTaskExecutor在后台去执行 它的run方法内部比较复杂,主要是调用mWorker.startWork(),以及在最后结尾调用了onWorkFinished,接下来一个个分析这2步都做了什么动作 首先看startWork方法,它是ListenableWorker中的方法,而ListenableWorker是Worker的父类,查看Worker,在它的startWork 中开启了一个线程池去执行dowork方法,到这一步,终于走完了整个调用过程,也就是我们创建的继承Worker类的testworker中的dowork方法会被调用,完成了后台任务的执行。当我们的dowork执行完毕后,会返回该结果,而这个结果在上面说了,是通过result进行了接收。而该状态会在onWorkFinished方法中进行更新。SystemJobScheduler的执行流程分析完毕。 ** ** 进入SystemAlarmScheduler的schedule方法,它会对传入的workSpecs进行遍历,并调用scheduleWorkSpec方法 而这个方法会调用createScheduleWorkIntent创建SystemAlarmService服务并将我们的workspecid进行传入,并开启该服务 除此之外,还可以通过反编译apk看出,系统自动为我们静态注册了很多系统广播, 查看该服务做了些什么,发现其内部创建了SystemAlarmDispatcher对象,并在onStartCommand中调用了其add方法 在该add方法中,会将我们传递进来的intent放入到mIntents中去,该mIntents是一个intent的list集合,并在最后调用了processCommand方法 该方法内会将我们的intent传递给mCommandHandler.onHandleIntent去处理 这个方法内使用到了状态模式,会对intent的action进行判断,并做不同的处理,当我们第一次进入时会进入handleScheduleWorkIntent 查看handleReschedule做了什么,该方法会调用WorkManagerImpl的rescheduleEligibleWork 在这个方法内会将我们的任务状态进行更新,并重新调用Schedulers.schedule 查看handleScheduleWorkIntent,这里会判断workSpec是否存在约束,最终会走到Alarms.setAlarm中去,区别在于如果存在约束,则会调用完Alarms.setAlarm之后通过CommandHandler.createConstraintsChangedIntent构建一个intent意图发送给Dispatcher,然后重新进行一次回调 查看 该AddRunnable 的run方法,会重新调用dispatcher的add方法,此时的intent的action已经发生了变化,所以当再次走到onHandleIntent方法时,就会走不同的调用渠道。(状态模式) 继续查看setAlarm, 这个方法内,会通过数据库中根据workSpecId去获取对应的系统编号,如果没有则会获取一个系统编号,并注册到数据库中去,他们最终都调用了setExactAlarm方法 在这里会获取AlarmManager,它属于系统服务之一的定时服务,会根据指定的意图,在合适的时间去调用所对应的SystemAlarmService,在这里会通过CommandHandler.createDelayMetIntent去创建一个inent,并放入到了AlarmManager 该createDelayMetIntent创造的意图的action为ACTION_DELAY_MET 该定时服务会根据我们指定的PendingIntent,在合适的时间开启其对应的SystemAlarmService,并将对应的intent传递到SystemAlarmService中去,上面说过了在该SystemAlarmService的onStartCommand方法中调用了Dispatcher.add方法且将intent作为参数,这个方法最终又执行到了onHandleIntent方法,且此时的intent.action发生了变化,所以会走不同的渠道(状态模式) 通过反编译apk看出,该service由程序自动生成,无需手动实现 上面分析了,执行了setAlarm方法后,会重新构建一个intent并放入到了SystemAlarmService中,而该intent的action为ACTION_DELAY_MET,所以当再次执行到onHandleIntent时,就调用到了handleDelayMet方法 该方法主要执行了delayMetCommandHandler.handleProcessWork 在handleProcessWork中,会根据是否有约束选择调用onAllConstraintsMet与mWorkConstraintsTracker.replace 如果没有约束则在这个方法内,调用了Dispatcher.getProcessor().startWork(mWorkSpecId);最终完成了worker的执行 (上面有讲该执行的过程) 再查看其有约束的情况下怎么处理, WorkConstraintsTracker.replace执行过程 查看WorkConstraintsTracker.replace方法,在这里调用了controller.replace(workSpecs); replace主要就是遍历 workSpecs,并将有约束的workSpec添加到mMatchingWorkSpecIds,并在最后调用了updateCallback 这里updateCallback会根据约束情况来选择调用,而看源码可以发现这里是个回调方法,由WorkConstraintsTracker进行了实现 WorkConstraintsTracker的onConstraintMet主要是判断有约束条件的workSpecId的条件是否已经全部满足,如果满足则和不受约束的workSpecId做相同的处理,这里继续发生了回调 具体的方法调用是在DelayMetCommandHandler中,最终又走到了 到这里为止SystemAlarmScheduler的执行流程分析完毕 它的执行过程相比之下比较简单,如果worker(这里使用的是workspec,但其描述的是对应的worker,与该worker有关联关系,这里对workspec的判断,其实还是对worker执行条件的判断)不受约束,则直接调用WorkManagerImpl.startWork去执行worker,否则调用WorkConstraintsTracker.replace。 WorkConstraintsTracker.replace,这个方法之前已经分析过了,不过在GreedyScheduler中,我们最后一步步回调会调用到GreedyScheduler 可以发现在这2个方法中,对于符合条件和不符合条件的worker,循环遍历去执行或者做停止操作 查看WorkManagerImpl.startWork方法 发现最终也是调用了Processor().startWork 到此为止,3大调度器的工作流程和原理全部分析完毕
SystemJobScheduler的工作过程
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; }
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(); } } }
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); }
@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)); }
@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); } }
该方法过程的调用会在后面多次使用到
) 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<Boolean> 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; }
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<Data> 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<ListenableWorker.Result> 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(); } }
public final @NonNull ListenableFuture<Result> 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工作流程
public void schedule(WorkSpec... workSpecs) { for (WorkSpec workSpec : workSpecs) { scheduleWorkSpec(workSpec); } }
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; }
当我们接收到这些系统广播时,就会调用到createConstraintsChangedIntent,拉起SystemAlarmService,也就是当接收到这些广播时,SystemAlarmService会被拉起,然后根据传入的intent进行一系列操作,从而执行符合条件的workerabstract 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 { }
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(); } }
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; }
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(); } }
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)); } } } }
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(); }
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()); }
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; }
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方法 } }
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); } }
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; }
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); } } }
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)); } } }
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)); } }
public void onAllConstraintsMet(@NonNull List<String> 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(); } }
public void replace(@NonNull List<WorkSpec> workSpecs) { synchronized (mLock) { for (ConstraintController controller : mConstraintControllers) { controller.setCallback(null); } for (ConstraintController controller : mConstraintControllers) { controller.replace(workSpecs); } for (ConstraintController controller : mConstraintControllers) { controller.setCallback(this); } } }
public void replace(@NonNull List<WorkSpec> 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(); }
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(); }
public void onConstraintMet(@NonNull List<String> workSpecIds) { synchronized (mLock) { List<String> 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<String> workSpecIds) { synchronized (mLock) { if (mCallback != null) { mCallback.onAllConstraintsNotMet(workSpecIds); } } }
onAllConstraintsMet
方法,完成了整体调用 public void onAllConstraintsMet(@NonNull List<String> 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(); } }
GreedyScheduler的工作流程
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<WorkSpec> constrainedWorkSpecs = new ArrayList<>(); List<String> 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); } } }
public void replace(@NonNull List<WorkSpec> workSpecs) { synchronized (mLock) { for (ConstraintController controller : mConstraintControllers) { controller.setCallback(null); } for (ConstraintController controller : mConstraintControllers) { controller.replace(workSpecs); } for (ConstraintController controller : mConstraintControllers) { controller.setCallback(this); } } }
@Override public void onAllConstraintsMet(@NonNull List<String> 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<String> workSpecIds) { for (String workSpecId : workSpecIds) { Logger.get().debug(TAG, String.format("Constraints not met: Cancelling work ID %s", workSpecId)); mWorkManagerImpl.stopWork(workSpecId); //调用 mWorkManagerImpl.stopWork方法 } }
public void startWork(String workSpecId, WorkerParameters.RuntimeExtras runtimeExtras) { mWorkTaskExecutor .executeOnBackgroundThread( new StartWorkRunnable(this, workSpecId, runtimeExtras)); }
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); //在这里执行 } }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算