2024年安卓最新史上最详细!那些你不知道的WorkManager流程分析和源码解析,嵌入式软件开发面试题库

结尾

如何才能让我们在面试中对答如流呢?

答案当然是平时在工作或者学习中多提升自身实力的啦,那如何才能正确的学习,有方向的学习呢?为此我整理了一份Android学习资料路线:

这里是一份BAT大厂面试资料专题包:

好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划。来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。

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

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

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

//WorkManagerInitializer
public boolean onCreate() {
// Initialize WorkManager with the default configuration.
WorkManager.initialize(getContext(), new Configuration.Builder().build());
return true;
}

由于WorkManager是个单例,在此时WorkManager就已经被初始化了。在initialize()之前,会创建一个默认的Configuration。Configuration设置了许多属性,用来管理和调度工作的方式。通常我们使用WorkManager默认创建的Configuration即可。如需使用自己的Configuration,可参考官方文档,有明确的使用说明。我们继续看initialize()的实现,由于WorkManager是个抽象类,真正的构造方法是在他的子类WorkManagerImpl实现的:

//WorkManagerImpl
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
synchronized (sLock) {
if (sDelegatedInstance != null && sDefaultInstance != null) {
throw new IllegalStateException("WorkManager is already initialized. Did you "

  • "try to initialize it manually without disabling "
  • "WorkManagerInitializer? See "
  • "WorkManager#initialize(Context, Configuration) or the class level "
  • “Javadoc for more information.”);
    }

if (sDelegatedInstance == null) {
context = context.getApplicationContext();
if (sDefaultInstance == null) {
sDefaultInstance = new WorkManagerImpl(
context,
configuration,
new WorkManagerTaskExecutor(configuration.getTaskExecutor()));
}
sDelegatedInstance = sDefaultInstance;
}
}
}

此时sDelegatedInstance为null,WorkManager会先创建一个默认的WorkManagerTaskExecutor对象,用来执行WorkManager的任务。之后创建一个WorkManagerImpl对象:

//WorkManagerImpl
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor) {
this(context,
configuration,
workTaskExecutor,
context.getResources().getBoolean(R.bool.workmanager_test_configuration));
}

//WorkManagerImpl
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
boolean useTestDatabase) {
this(context,
configuration,
workTaskExecutor,
WorkDatabase.create(
context.getApplicationContext(),
workTaskExecutor.getBackgroundExecutor(),
useTestDatabase)
);
}

WorkManager在此时创建了数据库。WorkDatabase.create()将任务列表序列化到本地,记录每一个任务的属性,执行条件,执行顺序及执行状态等。从而保证任务在冷启动或硬件重启后,可以根据条件继续执行。接着看this()的实现:

//WorkManagerImpl
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
@NonNull WorkDatabase database) {
Context applicationContext = context.getApplicationContext();
Logger.setLogger(new Logger.LogcatLogger(configuration.getMinimumLoggingLevel()));
List schedulers = createSchedulers(applicationContext, workTaskExecutor);
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}

到这里有三个重要的初始化步骤。分别是createSchedulers()来根据Build Version创建不同的Schedulers进行任务调度,Processor()用来管理Schedulers的执行,和internalInit()真正的初始化。先看createSchedulers()的实现:

//WorkManagerImpl
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
public List createSchedulers(
@NonNull Context context,
@NonNull TaskExecutor taskExecutor) {

return Arrays.asList(
Schedulers.createBestAvailableBackgroundScheduler(context, this),
// Specify the task executor directly here as this happens before internalInit.
// GreedyScheduler creates ConstraintTrackers and controllers eagerly.
new GreedyScheduler(context, taskExecutor, this));
}

return一个Scheduler数组。其中GreedyScheduler()是常驻的,用来执行没有任何约束的非周期性的任务。接下来看createBestAvailableBackgroundScheduler()的实现。

//Scheduler
@NonNull
static Scheduler createBestAvailableBackgroundScheduler(
@NonNull Context context,
@NonNull WorkManagerImpl workManager) {

Scheduler scheduler;

if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
scheduler = new SystemJobScheduler(context, workManager);
setComponentEnabled(context, SystemJobService.class, true);
Logger.get().debug(TAG, “Created SystemJobScheduler and enabled SystemJobService”);
} else {
scheduler = tryCreateGcmBasedScheduler(context);
if (scheduler == null) {
scheduler = new SystemAlarmScheduler(context);
setComponentEnabled(context, SystemAlarmService.class, true);
Logger.get().debug(TAG, “Created SystemAlarmScheduler”);
}
}
return scheduler;
}

这段代码对build version进行了判断。若>=23,则返回SystemJobScheduler(),即利用JobScheduler进行任务管理。<23的时候先尝试使用GcmScheduler进行管理。若无法创建GcmScheduler则返回SystemAlarmScheduler()使用AlamManager进行任务管理。返回的这个Scheduler是用来执行周期性,或者有约束性的任务。由此可见,WorkManager创建了两个Scheduler,分别为执行非约束非周期性任务的GreedyScheduler,和执行约束性周期性任务的SystemJobScheduler/GcmBasedScheduler/SystemAlarmScheduler。
这几种Scheduler的构造和执行之后再分析。
之后初始化Processor。Processor存储了Configuration,TaskExecutor,WorkDatabase,schedulers等,用来在适当的时机进行任务调度。再来看internalInit():

//WorkManagerImpl
private void internalInit(@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
@NonNull WorkDatabase workDatabase,
@NonNull List schedulers,
@NonNull Processor processor) {

context = context.getApplicationContext();
mContext = context;
mConfiguration = configuration;
mWorkTaskExecutor = workTaskExecutor;
mWorkDatabase = workDatabase;
mSchedulers = schedulers;
mProcessor = processor;
mPreferenceUtils = new PreferenceUtils(workDatabase);
mForceStopRunnableCompleted = false;

// Checks for app force stops.
mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
}

记录了Configuration,TaskExecutor,WorkDatabase,schedulers,Processor等。然后我们看最后一行执行语句,启动了一个ForceStopRunnable,这个Runnable是干什么用的呢?直接看run()的实现:

//ForceStopRunnable
@Override
public void run() {
// Migrate the database to the no-backup directory if necessary.
WorkDatabasePathHelper.migrateDatabase(mContext);
// Clean invalid jobs attributed to WorkManager, and Workers that might have been
// interrupted because the application crashed (RUNNING state).
Logger.get().debug(TAG, “Performing cleanup operations.”);
try {
boolean needsScheduling = cleanUp();
if (shouldRescheduleWorkers()) {
Logger.get().debug(TAG, “Rescheduling Workers.”);
mWorkManager.rescheduleEligibleWork();
// Mark the jobs as migrated.
mWorkManager.getPreferenceUtils().setNeedsReschedule(false);
} else if (isForceStopped()) {
Logger.get().debug(TAG, “Application was force-stopped, rescheduling.”);
mWorkManager.rescheduleEligibleWork();
} else if (needsScheduling) {
Logger.get().debug(TAG, “Found unfinished work, scheduling it.”);
Schedulers.schedule(
mWorkManager.getConfiguration(),
mWorkManager.getWorkDatabase(),
mWorkManager.getSchedulers());
}
mWorkManager.onForceStopRunnableCompleted();
} catch (SQLiteCantOpenDatabaseException
| SQLiteDatabaseCorruptException
| SQLiteAccessPermException exception) {
// ForceStopRunnable is usually the first thing that accesses a database (or an app’s
// internal data directory). This means that weird PackageManager bugs are attributed
// to ForceStopRunnable, which is unfortunate. This gives the developer a better error
// message.
String message =
"The file system on the device is in a bad state. WorkManager cannot access "

  • “the app’s internal data store.”;
    Logger.get().error(TAG, message, exception);
    throw new IllegalStateException(message, exception);
    }
    }

这段代码的实现细节先不做深究。但是很明显,这个Runnable的作用就是在WorkManager初始化过程中,发现了未完成的,需要重新执行的任务,或者app被强制kill的情况下,直接对Scheduler进行调度。到此,一个WorkManager的初始化流程就完成了。

总结

  1. WorkManager的初始化是在app冷启动后,由WorkManagerInitializer这个ContentProvider执行的。
  2. 初始化过程包含了Configuration,WorkManagerTaskExecutor,WorkDatabase,Schedulers,Processor等的初始化过程。
  3. Schedulers有两个。
    (1) GreedyScheduler:执行没有任何约束的非周期性的任务。
    (2) SystemJobScheduler/GcmBasedScheduler/SystemAlarmScheduler:执行周期性或者有约束性的任务。优先返回SystemJobScheduler,在build version小于23的情况下先尝试返回GcmBasedScheduler,若返回为空再返回SystemAlarmScheduler。
  4. 初始化的最后,会根据情况找到需要被执行的任务进行调度执行。

WorkManager的初始化流程图:

4.1.2.WorkRequest的创建

梳理完WorkManager的初始化过程后,我们回到示例代码,创建一个OneTimeWorkRequest

val work1Request = OneTimeWorkRequestBuilder().build()

//OneTimeWorkRequest.Builder
/**

  • Creates a {@link OneTimeWorkRequest}.
  • @param workerClass The {@link ListenableWorker} class to run for this work
    */
    public Builder(@NonNull Class<? extends ListenableWorker> workerClass) {
    super(workerClass);
    mWorkSpec.inputMergerClassName = OverwritingInputMerger.class.getName();
    }

//WorkRequest.Builder
Builder(@NonNull Class<? extends ListenableWorker> workerClass) {
mId = UUID.randomUUID();
mWorkerClass = workerClass;
mWorkSpec = new WorkSpec(mId.toString(), workerClass.getName());
addTag(workerClass.getName());
}

OneTimeWorkRequest为builder对象创建了WorkSpec对象用来保存任务id和类名,其中id是通过UUID自动生成的。request的tag默认是通过类名生成的,外部也可调用addTag()方法设置标签。另外为WorkSpec设置了默认的任务输入流的合并规则:OverwritingInputMerger。接着看build()方法的实现:

//WorkRequest.Builder
public final @NonNull W build() {
W returnValue = buildInternal();
// Create a new id and WorkSpec so this WorkRequest.Builder can be used multiple times.
mId = UUID.randomUUID();
mWorkSpec = new WorkSpec(mWorkSpec);
mWorkSpec.id = mId.toString();
return returnValue;
}

buildInternal()方法返回了一个WorkRequest对象,这是个抽象方法,在子类OneTimeWorkRequest.Builder中的实现如下:

//OneTimeWorkRequest.Builder
@Override
@NonNull OneTimeWorkRequest buildInternal() {
if (mBackoffCriteriaSet
&& Build.VERSION.SDK_INT >= 23
&& mWorkSpec.constraints.requiresDeviceIdle()) {
throw new IllegalArgumentException(
“Cannot set backoff criteria on an idle mode job”);
}
if (mWorkSpec.runInForeground
&& Build.VERSION.SDK_INT >= 23
&& mWorkSpec.constraints.requiresDeviceIdle()) {
throw new IllegalArgumentException(
“Cannot run in foreground with an idle mode constraint”);
}
return new OneTimeWorkRequest(this);
}

由于我们没有为WorkSpec设置其他属性,目前也没有约束条件,所以直接返回一个OneTimeWorkRequest对象。

//OneTimeWorkRequest
OneTimeWorkRequest(Builder builder) {
super(builder.mId, builder.mWorkSpec, builder.mTags);
}

把Builder的id, WorkSpec对象和tag赋给OneTimeWorkRequest对象。再回到Builder的build()方法:

//OneTimeWorkRequest.Builder
public final @NonNull W build() {
W returnValue = buildInternal();
// Create a new id and WorkSpec so this WorkRequest.Builder can be used multiple times.
mId = UUID.randomUUID();
mWorkSpec = new WorkSpec(mWorkSpec);
mWorkSpec.id = mId.toString();
return returnValue;
}

在buildInternal()拿到OneTimeWorkRequest对象之后,为Builder创建了一个新的WorkSpec对象,并赋予了新的UUID。虽然与原先的WorkSpec对象中每个属性的值是一致的,但指向了不同的内存地址。这么做的目的是为了这个Builder对象可被重复利用。好了,现在我们一个任务的WorkRequest创建就完成了。

总结

WorkRequest的创建是为了持有三个重要的成员变量。分别是:

  1. mId:由UUID生成的任务id。
  2. mWorkSpec:每个任务的属性。
  3. mTags:每个任务的标签。

WorkRequest创建的流程图

image

4.2非约束条件任务的执行过程

执行OneTimeWorkRequest

WorkManager.getInstance(this).enqueue(work1Request)

根据第一节的分析,WorkManager是个单例,在app启动的时候就已经被初始化了。所以直接看enqueue()的实现:

//WorkManager
@NonNull
public final Operation enqueue(@NonNull WorkRequest workRequest) {
return enqueue(Collections.singletonList(workRequest));
}

//WorkManager
@NonNull
public abstract Operation enqueue(@NonNull List<? extends WorkRequest> requests);

//WorkManagerImpl
@NonNull
public Operation enqueue(
@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;
}

最后

**要想成为高级安卓工程师,必须掌握许多基础的知识。**在工作中,这些原理可以极大的帮助我们理解技术,在面试中,更是可以帮助我们应对大厂面试官的刁难。


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

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

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

essLint(“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;
}

最后

**要想成为高级安卓工程师,必须掌握许多基础的知识。**在工作中,这些原理可以极大的帮助我们理解技术,在面试中,更是可以帮助我们应对大厂面试官的刁难。


[外链图片转存中…(img-fOcVu5Q2-1715823118395)]

[外链图片转存中…(img-pN5IIOfr-1715823118395)]

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

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

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

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值