史上最详细!那些你不知道的WorkManager流程分析和源码解析

@NonNull List<? extends WorkRequest> workRequests) {

// This error is not being propagated as part of the Operation, as we want the
// app to crash during development. Having no workRequests is always a developer error.
if (workRequests.isEmpty()) {
throw new IllegalArgumentException(
“enqueue needs at least one WorkRequest.”);
}
return new WorkContinuationImpl(this, workRequests).enqueue();
}

创建一个WorkContinuationImpl()对象,再执行enqueue()方法。WorkContinuationImpl是WorkContinuation的子类。用来把多个OneTimeWorkRequest根据需求串行,并行或合并处理。我们熟悉的then(),combine(),enqueue()等都是这个类的方法。

//WorkContinuationImpl
WorkContinuationImpl(@NonNull WorkManagerImpl workManagerImpl,
String name,
ExistingWorkPolicy existingWorkPolicy,
@NonNull List<? extends WorkRequest> work,
@Nullable List parents) {
mWorkManagerImpl = workManagerImpl;
mName = name;
mExistingWorkPolicy = existingWorkPolicy;
mWork = work;
mParents = parents;
mIds = new ArrayList<>(mWork.size());
mAllIds = new ArrayList<>();
if (parents != null) {
for (WorkContinuationImpl parent : parents) {
mAllIds.addAll(parent.mAllIds);
}
}
for (int i = 0; i < work.size(); i++) {
String id = work.get(i).getStringId();
mIds.add(id);
mAllIds.add(id);
}
}

WorkContinuation保存了任务相关的所有信息,如WorkManager,WorkRequest,父WorkContinuation等。继续看WorkContinuationImpl的enqueue()方法的实现:

//WorkContinuationImpl
@Override
public @NonNull Operation enqueue() {
// Only enqueue if not already enqueued.
if (!mEnqueued) {
// The runnable walks the hierarchy of the continuations
// and marks them enqueued using the markEnqueued() method, parent first.
EnqueueRunnable runnable = new EnqueueRunnable(this);
mWorkManagerImpl.getWorkTaskExecutor().executeOnBackgroundThread(runnable);
mOperation = runnable.getOperation();
} else {
Logger.get().warning(TAG,
String.format(“Already enqueued work ids (%s)”, TextUtils.join(", ", mIds)));
}
return mOperation;
}

WorkManager的TaskExecutor执行了EnqueueRunnable。EnqueueRunnable中run()的实现:

//EnqueueRunnable
@Override
public void run() {
try {
if (mWorkContinuation.hasCycles()) {
throw new IllegalStateException(
String.format(“WorkContinuation has cycles (%s)”, mWorkContinuation));
}
boolean needsScheduling = addToDatabase();
if (needsScheduling) {
// Enable RescheduleReceiver, only when there are Worker’s that need scheduling.
final Context context =
mWorkContinuation.getWorkManagerImpl().getApplicationContext();
PackageManagerHelper.setComponentEnabled(context, RescheduleReceiver.class, true);
scheduleWorkInBackground();
}
mOperation.setState(Operation.SUCCESS);
} catch (Throwable exception) {
mOperation.setState(new Operation.State.FAILURE(exception));
}
}

addToDatabase()的作用是把WorkSpec存入到数据库,并对任务的状态进行校验。当前的case会返回true。PackageManagerHelper.setComponentEnabled()开启了RescheduleReceiver。通过反编译我们得知这个Receiver是在AndroidManifest中注册的,默认是disable的。监听了开机,时间变化,时区变化这三个广播。

//AndroidManifest






scheduleWorkInBackground()的实现:

//EnqueueRunnable
/**

  • Schedules work on the background scheduler.
    */
    @VisibleForTesting
    public void scheduleWorkInBackground() {
    WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
    Schedulers.schedule(
    workManager.getConfiguration(),
    workManager.getWorkDatabase(),
    workManager.getSchedulers());
    }

这部分就是任务调度的实现。拿到WorkManager对象后调用了Schedulers.schedule()方法,传入了Configuration, WorkDatabase, Scheduler这三个对象。执行schedule()方法:

//Schedulers
public static void schedule(
@NonNull Configuration configuration,
@NonNull WorkDatabase workDatabase,
List schedulers) {
if (schedulers == null || schedulers.size() == 0) {
return;
}

WorkSpecDao workSpecDao = workDatabase.workSpecDao();
List eligibleWorkSpecs;

workDatabase.beginTransaction();
try {
eligibleWorkSpecs = workSpecDao.getEligibleWorkForScheduling(
configuration.getMaxSchedulerLimit());
if (eligibleWorkSpecs != null && eligibleWorkSpecs.size() > 0) {
long now = System.currentTimeMillis();

// Mark all the WorkSpecs as scheduled.
// Calls to Scheduler#schedule() could potentially result in more schedules
// on a separate thread. Therefore, this needs to be done first.
for (WorkSpec workSpec : eligibleWorkSpecs) {
workSpecDao.markWorkSpecScheduled(workSpec.id, now);
}
}
workDatabase.setTransactionSuccessful();
} finally {
workDatabase.endTransaction();
}

if (eligibleWorkSpecs != null && eligibleWorkSpecs.size() > 0) {
WorkSpec[] eligibleWorkSpecsArray = eligibleWorkSpecs.toArray(new WorkSpec[0]);
// Delegate to the underlying scheduler.
for (Scheduler scheduler : schedulers) {
scheduler.schedule(eligibleWorkSpecsArray);
}
}
}

先进行了一系列的数据库操作,然后开始根据条件每个任务进行调度。其中eligibleWorkSpecs返回的是在ENQUEUED状态下,未被执行且未被取消的WorkSpec列表,然后更新这些任务的request状态到数据库。最后遍历schedulers调用scheduler.schedule()对每个任务进行调度处理。由于示例代码创建的是没有约束的一次性任务,所以看一下GreedyScheduler对于schedule()方法的实现:

//GreedyScheduler
@Override
public void schedule(@NonNull WorkSpec… workSpecs) {
if (mIsMainProcess == null) {
// The default process name is the package name.
mIsMainProcess = TextUtils.equals(mContext.getPackageName(), getProcessName());
}

if (!mIsMainProcess) {
Logger.get().info(TAG, “Ignoring schedule request in non-main process”);
return;
}

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) {
if (workSpec.state == WorkInfo.State.ENQUEUED
&& !workSpec.isPeriodic()
&& workSpec.initialDelay == 0L
&& !workSpec.isBackedOff()) {
if (workSpec.hasConstraints()) {
if (SDK_INT >= 23 && workSpec.constraints.requiresDeviceIdle()) {
// Ignore requests that have an idle mode constraint.
Logger.get().debug(TAG,
String.format(“Ignoring WorkSpec %s, Requires device idle.”,
workSpec));
} else if (SDK_INT >= 24 && workSpec.constraints.hasContentUriTriggers()) {
// Ignore requests that have content uri triggers.
Logger.get().debug(TAG,
String.format(“Ignoring WorkSpec %s, Requires ContentUri triggers.”,
workSpec));
} else {
constrainedWorkSpecs.add(workSpec);
constrainedWorkSpecIds.add(workSpec.id);
}
} else {
Logger.get().debug(TAG, String.format(“Starting work for %s”, workSpec.id));
mWorkManagerImpl.startWork(workSpec.id);
}
}
}

// 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()) {
Logger.get().debug(TAG, String.format(“Starting tracking for [%s]”,
TextUtils.join(“,”, constrainedWorkSpecIds)));
mConstrainedWorkSpecs.addAll(constrainedWorkSpecs);
mWorkConstraintsTracker.replace(mConstrainedWorkSpecs);
}
}
}

在: (1) WorkSpec是ENQUEUED的状态 (2) 非周期性任务 (3) 非延迟任务 (4) 非撤销的任务 (5) 没有其它约束的任务 满足这五个条件后,直接调用:

//GreedyScheduler
mWorkManagerImpl.startWork(workSpec.id);

让WorkManager直接去执行任务。继续看startWork()的实现:

//WorkManagerImpl
/**

  • @param workSpecId The {@link WorkSpec} id to start
  • @hide
    */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public void startWork(@NonNull String workSpecId) {
    startWork(workSpecId, null);
    }

//WorkManagerImpl
/**

  • @param workSpecId The {@link WorkSpec} id to start
  • @param runtimeExtras The {@link WorkerParameters.RuntimeExtras} associated with this work
  • @hide
    */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public void startWork(
    @NonNull String workSpecId,
    @Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
    mWorkTaskExecutor
    .executeOnBackgroundThread(
    new StartWorkRunnable(this, workSpecId, runtimeExtras));
    }

WorkTaskExecutor对任务进行了调度。StartWorkRunnable的run()的实现:

//StartWorkRunnable
@Override
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}

StartWorkRunnable会将任务的信息交给Processor,由Processor调用startWork()去执行任务:

//Processor
/**

  • Starts a given unit of work in the background.
  • @param id The work id to execute.
  • @param runtimeExtras The {@link WorkerParameters.RuntimeExtras} for this work, if any.
  • @return {@code true} if the work was successfully enqueued for processing
    */
    public boolean startWork(
    @NonNull String id,
    @Nullable 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,
this,
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;
}

startWork()方法中创建了一个WorkerWrapper的Runnable对象,交由WorkTaskExecutor调度处理。WorkerWrapper的run()方法的实现:

//WorkerWrapper
@WorkerThread
@Override
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
mWorkDescription = createWorkDescription(mTags);
runWorker();
}

//WorkerWrapper
private void runWorker() {
if (tryCheckForInterruptionAndResolve()) {
return;
}

mWorkDatabase.beginTransaction();
try {
mWorkSpec = mWorkSpecDao.getWorkSpec(mWorkSpecId);

mWorkDatabase.setTransactionSuccessful();
} finally {
mWorkDatabase.endTransaction();
}

// Merge inputs. This can be potentially expensive code, so this should not be done inside
// a database transaction.

WorkerParameters params = new WorkerParameters(
UUID.fromString(mWorkSpecId),
input,
mTags,
mRuntimeExtras,
mWorkSpec.runAttemptCount,
mConfiguration.getExecutor(),
mWorkTaskExecutor,
mConfiguration.getWorkerFactory(),
new WorkProgressUpdater(mWorkDatabase, mWorkTaskExecutor),
new WorkForegroundUpdater(mForegroundProcessor, mWorkTaskExecutor));

// Not always creating a worker here, as the WorkerWrapper.Builder can set a worker override
// in test mode.
if (mWorker == null) {
mWorker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
mAppContext,
mWorkSpec.workerClassName,
params);
}

// 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();
// 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();
future.setFuture(mInnerFuture);
} catch (Throwable e) {
future.setException(e);
}

}
});

// Avoid synthetic accessors.

}

这段代码很长,我们省略了一些判断步骤和与示例无关的参数设置。先创建一个WorkerParameters对象。然后调用mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback()方法创建Worker对象。

这个方法我们不展开了,返回的就是我们自己的Woker对象,即Worker1的实例。之后交由WorkTaskExecutor调度处理。在run()方法的实现,我们看到调用了mWorker.startWork()方法:

//ListenableWorker    @MainThread    public abstract @NonNull ListenableFuture startWork();

ListenableWorker是个抽象类,是所有Worker的父类。Worker1也继承Worker类,startWork()在Worker中的实现:

//Worker
@Override
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;
}

在run()的实现执行了doWork()方法,即执行了我们Worker1的doWork()方法。

//Worker1
class Worker1(appContext: Context, workerParams: WorkerParameters) :
Worker(appContext, workerParams) {

override fun doWork(): Result {
Thread.sleep(5000)
return Result.success()
}
}

在执行完这个任务后,返回了success。Worker也就执行完成了。回到WorkerWrapper的runWorker()方法看接下来的处理:

//WorkerWrapper
private void runWorker() {

final SettableFuture<ListenableWorker.Result> future = SettableFuture.create();
// 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();
future.setFuture(mInnerFuture);
} catch (Throwable e) {
future.setException(e);
}

}
});

// Avoid synthetic accessors.
final String workDescription = mWorkDescription;
future.addListener(new Runnable() {
@Override
@SuppressLint(“SyntheticAccessor”)
public void run() {
try {
// If the ListenableWorker returns a null result treat it as a failure.
ListenableWorker.Result result = future.get();
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;
}
} 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()返回了一个Future对象mInnerFuture,调用future.setFuture(mInnerFuture)去处理doWork()返回的result。再经过一系列判断后,最终执行了onWorkFinished()方法:

//WorkerWrapper
void onWorkFinished() {
boolean isWorkFinished = false;
if (!tryCheckForInterruptionAndResolve()) {
mWorkDatabase.beginTransaction();
try {
WorkInfo.State state = mWorkSpecDao.getState(mWorkSpecId);
mWorkDatabase.workProgressDao().delete(mWorkSpecId);
if (state == null) {
// state can be null here with a REPLACE on beginUniqueWork().
// Treat it as a failure, and rescheduleAndResolve() will
// turn into a no-op. We still need to notify potential observers
// holding on to wake locks on our behalf.
resolve(false);
isWorkFinished = true;
} else if (state == RUNNING) {
handleResult(mResult);
// Update state after a call to handleResult()
state = mWorkSpecDao.getState(mWorkSpecId);
isWorkFinished = state.isFinished();
} else if (!state.isFinished()) {
rescheduleAndResolve();
}
mWorkDatabase.setTransactionSuccessful();
} finally {
mWorkDatabase.endTransaction();
}
}

// Try to schedule any newly-unblocked workers, and workers requiring rescheduling (such as
// periodic work using AlarmManager). This code runs after runWorker() because it should
// happen in its own transaction.

// Cancel this work in other schedulers. For example, if this work was
// completed by GreedyScheduler, we should make sure JobScheduler is informed
// that it should remove this job and AlarmManager should remove all related alarms.
if (mSchedulers != null) {
if (isWorkFinished) {
for (Scheduler scheduler : mSchedulers) {
scheduler.cancel(mWorkSpecId);
}
}
Schedulers.schedule(mConfiguration, mWorkDatabase, mSchedulers);
}
}

在onWorkFinished()会对刚刚执行完毕的任务作进一步处理。首先获取任务的当前状态state,然后从db中删除这个任务,再根据state作进一步处理。在我们的示例中,这时候state应该是RUNNING,我们看一下handleResult(mResult)的实现:

//WorkerWrapper
private void handleResult(ListenableWorker.Result result) {
if (result instanceof ListenableWorker.Result.Success) {
Logger.get().info(
TAG,
String.format(“Worker result SUCCESS for %s”, mWorkDescription));
if (mWorkSpec.isPeriodic()) {
resetPeriodicAndResolve();
} else {
setSucceededAndResolve();
}

} else if (result instanceof ListenableWorker.Result.Retry) {
Logger.get().info(
TAG,
String.format(“Worker result RETRY for %s”, mWorkDescription));
rescheduleAndResolve();
} else {
Logger.get().info(
TAG,
String.format(“Worker result FAILURE for %s”, mWorkDescription));
if (mWorkSpec.isPeriodic()) {
resetPeriodicAndResolve();
} else {
setFailedAndResolve();
}
}
}

在handleResult()方法中会根据任务类型和result结果进行不同的处理。例如周期性的任务会重新将这个任务的状态设置为ENQUEUED,更新其他相关参数,并更新数据库。我们示例中已经完成的一次性任务将会被更新成SUCCEEDED的状态,具体的处理的过程就不展开了。handleResult()执行完毕后更新isWorkFinished。如果isWorkFinished为true,由于我们在GreedyScheduler已经处理了这个任务,为了避免这个任务被其他schedulers处理,WorkManager遍历了mSchedulers列表,并将这个任务从其他schedulers中移除。最后再次执行Schedulers.schedule()方法,schedule下一个任务。

总结

  1. 在WorkManager执行了enqueue()后,创建WorkContinuationImpl对象执行enqueue()方法。
  2. WorkContinuationImpl持有的EnqueueRunnable对象将任务添加到db,并交给Schedulers去调度。
  3. Schedulers将任务交给每一个Scheduler去处理。在我们的示例中,GreedyScheduler会先处理这个任务。
  4. GreedyScheduler经过一系列判断后,调用WorkManager的startWork()方法执行这种一次性,非延迟,无约束的任务。
  5. WorkManager持有的StartWorkRunnable对象会将任务交给Processor去处理,执行startWork()方法。
  6. Processor创建一个WorkerWrapper对象,由它去调用Worker的startWork()方法,执行我们自定义worker的任务,并返回相应的result。
  7. 任务完成后,WorkerWrapper会根据result对任务状态,db等进行更新,然后schedule下一个任务。

WorkManager任务执行流程图:

4.3带约束的任务的执行过程

上面的章节我们分析了一个没有约束条件的一次性任务的执行过程。接下来我们来分析一个带约束条件的任务的执行过程。
创建一个非低电量才能执行的任务:

val constraints = Constraints.Builder()
.setRequiresBatteryNotLow(true)
.build()
val work2Request = OneTimeWorkRequestBuilder()
.setConstraints(constraints)
.build()
WorkManager.getInstance(this).enqueue(work2Request)

任务的创建过程中,会为WorkSpec添加Constraints属性。

public final @NonNull B setConstraints(@NonNull Constraints constraints) {
mWorkSpec.constraints = constraints;
return getThis();
}

在任务执行的过程中,由于增加了约束条件,根据之前章节的分析,常驻的GreedyScheduler的schedule()方法将不会startWork(),而是根据build version交由SystemJobScheduler或SystemAlarmScheduler进行处理。先来看使用SystemJobScheduler的情况:

4.3.1.SystemJobScheduler(Build Version >=23)

SystemJobScheduler使用的是JobScheduler来调度执行任务。由于JobScheduler的实现过程分析不在本文的讨论范围,所以只看WorkManager是如何使用JobScheduler进行任务调度的。通常JobScheduler的使用步骤如下:

  1. 创建JobService。
  2. 配置JobInfo。
  3. 执行。

SystemJobService: SystemJobService是执行任务的服务类,在onStartJob()中,会调用WorkManagerImpl的startWork()执行任务。

//SystemJobService
@Override
public boolean onStartJob(@NonNull JobParameters params) {
… …

String workSpecId = getWorkSpecIdFromJobParameters(params);
… …

synchronized (mJobParameters) {
… …
mJobParameters.put(workSpecId, params);
}

… …
mWorkManagerImpl.startWork(workSpecId, runtimeExtras);
return true;
}

SystemJobScheduler: 在初始化SystemJobScheduler的时候会获取JobScheduler对象:

//SystemJobScheduler
public SystemJobScheduler(@NonNull Context context, @NonNull WorkManagerImpl workManager) {
this(context,
workManager,
(JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE),
new SystemJobInfoConverter(context));
}

SystemJobScheduler的schedule()方法执行了scheduleInternal():

//SystemJobScheduler
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 {
mJobScheduler.schedule(jobInfo);
} catch (IllegalStateException e) {
… …
throw new IllegalStateException(message, e);
} catch (Throwable throwable) {
// OEM implementation bugs in JobScheduler cause the app to crash. Avoid crashing.
Logger.get().error(TAG, String.format(“Unable to schedule %s”, workSpec), throwable);
}
}

SystemJobInfoConverter.convert()方法就是创建了一个JobInfo,并将Constraints里的约束条件赋予JobInfo对象,之后便执行了JobScheduler.schedule(),根据约束条件对任务进行调度。

4.3.2. SystemAlarmScheduler(Build Version <23)

SystemAlarmScheduler使用的是AlarmManager来调度执行任务。由于AlarmManager的实现过程分析不在本文的讨论范围,所以只看WorkManager是如何使用AlarmManager进行任务调度的。反编译apk后,在AndroidManifest里有如下receiver注册:

在电量变化时,收到BATTERY_LOW的广播。在BatteryNotLowProxy的onReceive()进行处理:

//ConstraintProxy
public static class BatteryNotLowProxy extends 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);
}

createConstraintsChangedIntent()的执行如下:

//ConstraintProxy
static Intent createConstraintsChangedIntent(@NonNull Context context) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_CONSTRAINTS_CHANGED);
return intent;
}

SystemAlarmService的onStartCommand()处理如下:

@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;
}

调用了SystemAlarmDispatcher.add()方法。

//SystemAlarmDispatcher
@MainThread
public boolean add(@NonNull final Intent intent, final int startId) {
… …
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);
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;
}

add()方法中执行了processCommand(),这段代码的核心执行语句是:

//SystemAlarmDispatcher
mCommandHandler.onHandleIntent(mCurrentIntent, startId,
SystemAlarmDispatcher.this);

在CommandHandler的onHandleIntent()方法中,action为ACTION_CONSTRAINTS_CHANGED的执行是:

//CommandHandler
if (ACTION_CONSTRAINTS_CHANGED.equals(action)) {
handleConstraintsChanged(intent, startId, dispatcher);
}

//CommandHandler
private void handleConstraintsChanged(
@NonNull Intent intent, int startId,
@NonNull SystemAlarmDispatcher dispatcher) {

Logger.get().debug(TAG, String.format(“Handling constraints changed %s”, intent));
// Constraints changed command handler is synchronous. No cleanup
// is necessary.
ConstraintsCommandHandler changedCommandHandler =
new ConstraintsCommandHandler(mContext, startId, dispatcher);
changedCommandHandler.handleConstraintsChanged();
}

在handleConstraintsChanged()方法的执行中,会创建一个action为ACTION_DELAY_MET的Intent然后由SystemAlarmDispatcher发送出去,实际上也是调用了SystemAlarmDispatcher.add()方法。回到SystemAlarmDispatcher的add()流程。

//ConstraintsCommandHandler
Intent intent = CommandHandler.createDelayMetIntent(mContext, workSpecId);
Logger.get().debug(TAG, String.format(
“Creating a delay_met command for workSpec with id (%s)”, workSpecId));
mDispatcher.postOnMainThread(
new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId));

回到onHandleIntent()方法,在CommandHandler的onHandleIntent()方法中,action为ACTION_DELAY_MET的执行是:

//CommandHandler
else if (ACTION_DELAY_MET.equals(action)) {
handleDelayMet(intent, startId, dispatcher);
}

handleDelayMet()的执行过程,会调用DelayMetCommandHandler的handleProcessWork()方法,接着执行onAllConstraintsMet():

@Override
public void onAllConstraintsMet(@NonNull List workSpecIds) {
… …
synchronized (mLock) {
if (mCurrentState == STATE_INITIAL) {
… …
boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId);
… …
} else {
Logger.get().debug(TAG, String.format(“Already started work for %s”, mWorkSpecId));
}
}

最后

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。

还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

Android 基础知识点

Java 基础知识点

Android 源码相关分析

常见的一些原理性问题

希望大家在今年一切顺利,进到自己想进的公司,共勉!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


synchronized (mLock) {
if (mCurrentState == STATE_INITIAL) {
… …
boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId);
… …
} else {
Logger.get().debug(TAG, String.format(“Already started work for %s”, mWorkSpecId));
}
}

最后

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。

还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

Android 基础知识点

Java 基础知识点

Android 源码相关分析

常见的一些原理性问题

[外链图片转存中…(img-GrvyD1K6-1714584751415)]

希望大家在今年一切顺利,进到自己想进的公司,共勉!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值