目录
源码篇 上一篇中我们了解了WorkManager使用的的主要组件,猜测了各个组件的作用,并简单介绍了WorkManager是如何初始化的。本篇将延续前文,介绍WorkManager中Service组件之一的SystemAlarmService。
SystemAlarmService
Service invoked by {@link android.app.AlarmManager} to run work tasks.
服务将被AlarmManager调用来执行工作任务.
注: 此节中凡 描述中的 “命令” 及 “intent” 均指代包括 [规划任务、重新规划任务、约束条件改变、执行完毕、延时执行、停止执行…] 的事件,可视作状态模式。
如何处置命令 (processCommand)
SystemAlarmService 主要逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SystemAlarmService extends LifecycleService implements SystemAlarmDispatcher .CommandsCompletedListener { @Override public int onStartCommand (Intent intent, int flags, int startId) { super .onStartCommand(intent, flags, startId); if (intent != null ) { mDispatcher.add(intent, startId); } return Service.START_REDELIVER_INTENT; } }
我们看到, 此服务在创建时初始化并绑定闹钟事件调度器,当服务被start时,若有intent事件,则将intent传递给调度器. 调度器收到intent后执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @MainThread public boolean add (@NonNull final Intent intent, final int startId) { assertMainThread(); synchronized (mIntents) { boolean hasCommands = !mIntents.isEmpty(); mIntents.add(intent); if (!hasCommands) { processCommand(); } } return true ; }
当闹钟调度器收到新命令,会将新命令放入命令集合,若新命令为集合中第一个命令则直接进入执行命令逻辑中,否则不处理,前一命令执行完毕后再次调用执行命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @MainThread private void processCommand () { mWorkManager.getWorkTaskExecutor().executeOnBackgroundThread(new Runnable() { try { mCommandHandler.onHandleIntent(mCurrentIntent, startId, SystemAlarmDispatcher.this ); } catch (Throwable throwable) {} finally { postOnMainThread( new DequeueAndCheckForCompletion(SystemAlarmDispatcher.this )); } } }
当processCommand
被调用,将开启新的线程处理命令,主要干了两件事:
将命令交给CommandHandler分发[规划任务、重新规划任务、约束条件改变、执行完毕…]事件
将事件处理完毕回调到闹钟事件调度器,由调度器处理后续事宜。
我们来依次跟进这两件事:
CommandHandler如何分发命令
我们前面看到processCommand
中调用CommandHandler
分发命令,其代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @WorkerThread void onHandleIntent (@NonNull Intent intent,int startId, @NonNull SystemAlarmDispatcher dispatcher) { String action = intent.getAction(); if (ACTION_CONSTRAINTS_CHANGED.equals(action)) { handleConstraintsChanged(intent, startId, dispatcher); } else if (ACTION_RESCHEDULE.equals(action)) { handleReschedule(intent, startId, dispatcher); } else { Bundle extras = intent.getExtras(); if (!hasKeys(extras, KEY_WORKSPEC_ID)) { } else { 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, dispatcher); } else if (ACTION_EXECUTION_COMPLETED.equals(action)) { handleExecutionCompleted(intent, startId); } else { } } } }
我们看到这里主要依据命令(intent)的action执行命令分发操作,此处我们主要关注handleDelayMet
时延结束后,处理任务的主线:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private void handleDelayMet ( @NonNull Intent intent, int startId, @NonNull SystemAlarmDispatcher dispatcher) { Bundle extras = intent.getExtras(); synchronized (mLock) { String workSpecId = extras.getString(KEY_WORKSPEC_ID); if (!mPendingDelayMet.containsKey(workSpecId)) { DelayMetCommandHandler delayMetCommandHandler = new DelayMetCommandHandler(mContext, startId, workSpecId, dispatcher); mPendingDelayMet.put(workSpecId, delayMetCommandHandler); delayMetCommandHandler.handleProcessWork(); } else { } } }
我们可以看到,CommandHandler
中维护了一个 mPendingDelayMet的Map来保证单次任务不被多次处理,若命令未被处理过,则将其加入到队伍中,然后调用delayMetCommandHandler.handleProcessWork()
去处理任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @WorkerThread void handleProcessWork () { mWakeLock = WakeLocks.newWakeLock(...); WorkSpec workSpec = mDispatcher.getWorkManager().getWorkDatabase().workSpecDao().getWorkSpec(mWorkSpecId); if (workSpec == null ) { stopWork(); return ; } mHasConstraints = workSpec.hasConstraints(); if (!mHasConstraints) { onAllConstraintsMet(Collections.singletonList(mWorkSpecId)); } else { mWorkConstraintsTracker.replace(Collections.singletonList(workSpec)); } }
这里判断了任务状态及约束状态,依据约束状态执行任务或更新任务状态, 执行任务时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public void onAllConstraintsMet(@NonNull List<String> workSpecIds) { // 保证任务正确 if (!workSpecIds.contains(mWorkSpecId)) { return; } // 保证执行安全 synchronized (mLock) { if (mCurrentState == STATE_INITIAL) { // 更改状态 mCurrentState = STATE_START_REQUESTED; // startWork => doWork //这里没有使用WorkManagerImpl#startWork(),因为我们需要知道处理器是否在这里将工作排队 boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId); // 若任务状态是轮询 if (isEnqueued) { // 设置计时器以强制已进入队列的任务配额 mDispatcher.getWorkTimer() .startTimer(mWorkSpecId, WORK_PROCESSING_TIME_IN_MS, this); } else { // 执行完毕或取消,则清除状态 cleanUp(); } } else { Logger.get().debug(TAG, String.format("Already started work for %s", mWorkSpecId)); } } }
这里最终改变任务状态并调用Processor.startWork()
执行任务,我们将关注Processor.startWork()
,这个方法最终执行到我们定义的Worker中doWork()
方法,并且前面说到的WorkManager中负责任务执行的Service们最终都会调用到Processor.startWork()
。
由于内容流程较长且属于公共流程,关于Processor.startWork()
将单独整理未一小节,点击此处查看 。
DequeueAndCheckForCompletion如何完成回调
DequeueAndCheckForCompletion
是一个Runnable对象,postOnMainThread
时调用run:
1 2 3 4 @Override public void run () { mDispatcher.dequeueAndCheckForCompletion(); }
最终回调到dequeueAndCheckForCompletion
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void dequeueAndCheckForCompletion() { // 保证mIntents命令集只进或只出 synchronized (mIntents) { if (mCurrentIntent != null) { // 从命令集中移除已完成(第一个)命令 if (!mIntents.remove(0).equals(mCurrentIntent)) { throw new IllegalStateException("something"); } mCurrentIntent = null; } SerialExecutor serialExecutor = mTaskExecutor.getBackgroundExecutor(); // 若无预计执行和待执行命令,则通知SystemAlarmService执行完毕 if (!mCommandHandler.hasPendingCommands() && mIntents.isEmpty() && !serialExecutor.hasPendingTasks()) { if (mCompletedListener != null) { mCompletedListener.onAllCommandsCompleted(); } } else if (!mIntents.isEmpty()) { // 若命令集中还有未执行的命令,则继续执行 processCommand(); } } }
此时,若当前命令存在,则从命令集中移除当前命令。若无预计执行和待执行命令,则调用mCompletedListener.onAllCommandsCompleted()
通知SystemAlarmService执行完毕;若命令集合中还有未执行命令,则调用processCommand()
继续执行。
而SystemAlarmService.onAllCommandsCompleted()
最终会执行stopSelf()
停止服务
假装下面是时序图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 SystemAlarmService.java |- initializeDispatcher(); |- SystemAlarmService.onStartCommand() |- SystemAlarmDispatcher.add() |- mIntents.add(intent); |- SystemAlarmDispatcher.processCommand() |- try CommandHandler.onHandleIntent() |- ACTION_CONSTRAINTS_CHANGED |- ... |- ACTION_DELAY_MET |- delayMetCommandHandler.handleProcessWork() |- onAllConstraintsMet() |- mDispatcher.getProcessor().startWork() |- finally postOnMainThread ( new DequeueAndCheckForCompletion(SystemAlarmDispatcher.this ) ) |- SystemAlarmDispatcher.dequeueAndCheckForCompletion () |- mIntents.remove (0 ) ; |- CommandsCompletedListener.onAllCommandsCompleted() OR SystemAlarmDispatcher.processCommand()