概述
上一篇我们聊到了 WorkManager
的简单使用,接着我们来看一看 WorkManager
源码,他是怎么如何执行 Work
的。
当我们使用 WorkManager
创建任务时,WorkManager
会默认在 Manifest
中注册一系列的活动以及 androidx.startup.InitializationProvider
。如下图
在这个 Provider
中我们发现会默认注册一个 WorkManagerInitializer
的类。
/**
* Initializes {@link androidx.work.WorkManager} using {@code androidx.startup}.
*/
public final class WorkManagerInitializer implements Initializer<WorkManager> {
private static final String TAG = Logger.tagWithPrefix("WrkMgrInitializer");
@NonNull
@Override
public WorkManager create(@NonNull Context context) {
// Initialize WorkManager with the default configuration.
Logger.get().debug(TAG, "Initializing WorkManager with default configuration.");
WorkManager.initialize(context, new Configuration.Builder().build());
return WorkManager.getInstance(context);
}
@NonNull
@Override
public List<Class<? extends androidx.startup.Initializer<?>>> dependencies() {
return Collections.emptyList();
}
}
看注释我们知道,WorkManagerInitializer
会有 startup
进行初始化,最终会调用到 onCreate
方法。该方法中会调用 WorkManager.initialize
方法,并且传入了两个参数 context
、 Configuration
,这里我们看下 Configuration
里面有些什么。
public final class Configuration {
// 构造方法
Configuration(@NonNull Configuration.Builder builder) {
if (builder.mExecutor == null) {
mExecutor = createDefaultExecutor(false);
} else {
mExecutor = builder.mExecutor;
}
if (builder.mTaskExecutor == null) {
mIsUsingDefaultTaskExecutor = true;
mTaskExecutor = createDefaultExecutor(true);
} else {
mIsUsingDefaultTaskExecutor = false;
mTaskExecutor = builder.mTaskExecutor;
}
if (builder.mWorkerFactory == null) {
mWorkerFactory = WorkerFactory.getDefaultWorkerFactory();
} else {
mWorkerFactory = builder.mWorkerFactory;
}
if (builder.mInputMergerFactory == null) {
mInputMergerFactory = InputMergerFactory.getDefaultInputMergerFactory();
} else {
mInputMergerFactory = builder.mInputMergerFactory;
}
if (builder.mRunnableScheduler == null) {
mRunnableScheduler = new DefaultRunnableScheduler();
} else {
mRunnableScheduler = builder.mRunnableScheduler;
}
···
}
private @NonNull Executor createDefaultExecutor(boolean isTaskExecutor) {
return Executors.newFixedThreadPool(
// This value is the same as the core pool size for AsyncTask#THREAD_POOL_EXECUTOR.
Math.max(2, Math.min(Runtime.getRuntime().availableProcessors() - 1, 4)),
createDefaultThreadFactory(isTaskExecutor));
}
}
Configuration
构造方法中调用了 createDefaultExecutor(true);
方法,创建了固定大小的线程池用于后面执行 work
,以及 InputMergerFactory
用于数据合并的工厂类等等。简单的说 Configuration
就是为 WorkManager
配置一些基础的设施。看完 Configuration
我们接着走 WorkManager.initialize
方法,最终调用到了 WorkManagerImpl.initialize
方法。
// WorkManagerImpl
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class WorkManagerImpl extends WorkManager {
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;
}
}
}
}
看 WorkManagerImpl
源码我们看到 initialize
方法中初始化了一个 WorkManagerImpl
对象,并且传入了一个 WorkManagerTaskExecutor
的一个对象。这里我们先看下 WorkManagerTaskExecutor
是个啥
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class WorkManagerTaskExecutor implements TaskExecutor {
public WorkManagerTaskExecutor(@NonNull Executor backgroundExecutor) {
// Wrap it with a serial executor so we have ordering guarantees on commands
// being executed.
mBackgroundExecutor = new SerialExecutor(backgroundExecutor);
}
}
WorkManagerTaskExecutor
里面创建了一个 SerialExecutor
对象,OK 我们看下 SerialExecutor
类
public class SerialExecutor implements Executor {
private final ArrayDeque<Task> mTasks;
private final Executor mExecutor;
private final Object mLock;
private volatile Runnable mActive;
public SerialExecutor(@NonNull Executor executor) {
mExecutor = executor;
mTasks = new ArrayDeque<>();
mLock = new Object();
}
@Override
public void execute(@NonNull Runnable command) {
synchronized (mLock) {
mTasks.add(new Task(this, command));
if (mActive == null) {
scheduleNext();
}
}
}
}
在 SerialExecutor
里面初始化了一个 ArrayDeque
双端队列,用于保证后期创建的任务顺序执行。注意 Executor
是 Configuration
中创建的固定大小线程池。简单的说最终执行任务的就是 Configuration
中的固定大小线程池并且在执行任务的时候保证线性执行。分析完 WorkManagerTaskExecutor
我们回到 WorkManagerImpl.initialize
方法。接着会走到下面这个构造方法
@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));
}
public WorkManagerImpl(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
boolean useTestDatabase) {
this(context,
configuration,
workTaskExecutor,
WorkDatabase.create(
context.getApplicationContext(),
workTaskExecutor.getBackgroundExecutor(),
useTestDatabase)
);
}
并且从 R.bool.workmanager_test_configuration
获取当前是否是测试,并且 WorkDatabase
会根据当前的 Executor
生成数据库。WorkDatabase
通过 RoomDatabase
创建了一个数据库。有兴趣的朋友可以自己去看下,我们接着往下走
@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<Scheduler> schedulers =
createSchedulers(applicationContext, configuration, workTaskExecutor);
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}
OK,在该方法中会调用 createSchedulers
方法,我们看下这个方法
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
public List<Scheduler> createSchedulers(
@NonNull Context context,
@NonNull Configuration configuration,
@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, configuration, taskExecutor, this));
}
在 createSchedulers
方法中会调用 Schedulers
类的 createBestAvailableBackgroundScheduler
方法
// Schedulers
@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;
}
从该方法中我们可以知道,当前SDK版本>23的情况下,是由jobservice提供调用支持,如果是小于23的情况下是AlarmService提供调用
,这里就对应了 WorkManager 简介 中的
到这里 WorkManager
实例已经创建的差不多了,初始化基本上已经结束了。
接着我们看下他是如何区执行一个 Work
,我们看下面的栗子
val request = OneTimeWorkRequest.Builder(BlurWorker::class.java).build() // 第一种写法
WorkManager.getInstance(this).enqueue(request)
当我们执行一个 Work
的时候, WorkManager
调用 enqueue
最终会调用到 WorkManagerImpl.enqueue
的方法
// WorkManagerImpl
@Override
@NonNull
public Operation enqueue(
@NonNull List<? extends WorkRequest> requests) {
// 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 (requests.isEmpty()) {
throw new IllegalArgumentException(
"enqueue needs at least one WorkRequest.");
}
return new WorkContinuationImpl(this, requests).enqueue();
}
在 enqueue
方法中,会调用 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;
}
在这个方法中会将 WorkContinuationImpl
的实例放到一个 EnqueueRunnable
交给线程池执行,我们开始分析过这个线程池就是 WorkManager
初始化的时候 Configuration
创建的固定大小线程池。OK,最终就会执行 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));
}
}
在 run
方法中首先会调用 addToDatabase
根据策略不同将任务添加到数据库或者移除。然后会调用 PackageManagerHelper
将允许将 RescheduleReceiver
注册到 manifest.xml
内,我们可以打开编译后 apk
的 AndroidManifests.xml
看到对应的 recevier
。最终调用 scheduleWorkInBackground
方法
@VisibleForTesting
public void scheduleWorkInBackground() {
WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
Schedulers.schedule(
workManager.getConfiguration(),
workManager.getWorkDatabase(),
workManager.getSchedulers());
}
最终会调用 Schedulers.schedule
方法
public static void schedule(
@NonNull Configuration configuration,
@NonNull WorkDatabase workDatabase,
List<Scheduler> schedulers) {
···
try {
// Enqueued workSpecs when scheduling limits are applicable.
eligibleWorkSpecsForLimitedSlots = workSpecDao.getEligibleWorkForScheduling(
configuration.getMaxSchedulerLimit());
···
} finally {
workDatabase.endTransaction();
}
if (eligibleWorkSpecsForLimitedSlots != null
&& eligibleWorkSpecsForLimitedSlots.size() > 0) {
WorkSpec[] eligibleWorkSpecsArray =
new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
eligibleWorkSpecsArray =
eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);
// Delegate to the underlying schedulers.
for (Scheduler scheduler : schedulers) {
if (scheduler.hasLimitedSchedulingSlots()) {
scheduler.schedule(eligibleWorkSpecsArray);
}
}
}
}
在 Schedulers.schedule
方法中,会调用 workSpecDao.getEligibleWorkForScheduling
方法获取到需要执行的任务数据。最终调用到 scheduler.schedule
方法
// GreedyScheduler
@Override
public void schedule(@NonNull WorkSpec... workSpecs) {
...
for (WorkSpec workSpec : workSpecs) {
...
if (workSpec.state == WorkInfo.State.ENQUEUED) {
...
} else {
Logger.get().debug(TAG, String.format("Starting work for %s", workSpec.id));
mWorkManagerImpl.startWork(workSpec.id);
}
}
}
...
}
看代码可以看到,最终会执行到 WorkManagerImpl.startWork
方法中
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void startWork(@NonNull String workSpecId) {
startWork(workSpecId, null);
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void startWork(
@NonNull String workSpecId,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkTaskExecutor
.executeOnBackgroundThread(
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
最终会执行到 StartWorkRunnable
的 run
方法
@Override
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}
接着会执行到 Processor.startWork
方法,看源码
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 (isEnqueued(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<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;
}
首先在 Processor.startWork
方法中,会把数据封装成 WorkerWrapper
,然后将封装后的 WorkerWrapper
交给 BackgroundExecutor
进行执行。看源码我们知道 WorkerWrapper
实现了 Runnable
接口,最终就执行到了 WorkerWrapper
的 run
方法
// WorkerWrapper
@WorkerThread
@Override
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
mWorkDescription = createWorkDescription(mTags);
runWorker();
}
private void runWorker() {
...
Data input;
if (mWorkSpec.isPeriodic()) {
input = mWorkSpec.input;
} else {
InputMergerFactory inputMergerFactory = mConfiguration.getInputMergerFactory();
String inputMergerClassName = mWorkSpec.inputMergerClassName;
InputMerger inputMerger =
inputMergerFactory.createInputMergerWithDefaultFallback(inputMergerClassName);
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);
}
final WorkerParameters params = new WorkerParameters(
UUID.fromString(mWorkSpecId),
input,
mTags,
mRuntimeExtras,
mWorkSpec.runAttemptCount,
mConfiguration.getExecutor(),
mWorkTaskExecutor,
mConfiguration.getWorkerFactory(),
new WorkProgressUpdater(mWorkDatabase, mWorkTaskExecutor),
new WorkForegroundUpdater(mWorkDatabase, mForegroundProcessor, mWorkTaskExecutor));
if (mWorker == null) {
mWorker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
mAppContext,
mWorkSpec.workerClassName,
params);
}
if (trySetRunning()) {
...
final SettableFuture<ListenableWorker.Result> future = SettableFuture.create();
final WorkForegroundRunnable foregroundRunnable =
new WorkForegroundRunnable(
mAppContext,
mWorkSpec,
mWorker,
params.getForegroundUpdater(),
mWorkTaskExecutor
);
mWorkTaskExecutor.getMainThreadExecutor().execute(foregroundRunnable);
final ListenableFuture<Void> runExpedited = foregroundRunnable.getFuture();
runExpedited.addListener(new Runnable() {
@Override
public void run() {
try {
runExpedited.get();
Logger.get().debug(TAG,
String.format("Starting work for %s", mWorkSpec.workerClassName));
// Call mWorker.startWork() on the main thread.
mInnerFuture = mWorker.startWork();
future.setFuture(mInnerFuture);
} catch (Throwable e) {
future.setException(e);
}
}
}, mWorkTaskExecutor.getMainThreadExecutor());
...
} else {
resolveIncorrectStatus();
}
}
代码比较多这里看重点,首先会对数据进行处理,存在相同的 key 值,ArrayCreatingInputMerger 将每个键与数组配对。如果每个键都是唯一的,您会得到一系列一元数组。
最终将数据封装成 WorkerParameters
并且创建 WorkForegroundRunnable
,监听他的回调最终就执行了 mWorker.startWork()
接着看 Worker
的源码
// Worker
@WorkerThread
public abstract @NonNull Result doWork();
@Override
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;
}
到这里就回调到了我们自定义的 Worker
的 doWork
方法。到这里完整的调用已经结束了
总结下
-
架构上用
JobService
或AlarmService
进行调用执行 -
数据传递上用
Database
进行存储 -
执行角度利用线程池提供具体执行能力