https://developer.android.com/topic/libraries/architecture/workmanager/

Android新技术之从Service到WorkManager
WorkManager 流程分析和源码解析 | 开发者说·DTalk

保证任务一定会被执行 WorkManager 有自己的数据库,每一个任务的信息与任务状态,都会保存在本地数据库中。所以即使程序没有在运行,或者在设备重启等情况下,WorkManager 依然可以保证任务的执行,只是不保证任务立即被执行。
合理使用设备资源 在执行很多周期性或非立即执行的任务时,WorkManager 提供我们 API,帮助我们合理利用设备资源,避免不必要的内存,流量,电量等消耗。
WorkManager 的使用非常简单,分为如下几个步骤:
这个章节将会从以下几个方面梳理 WorkManager 的流程与源码:
首先梳理一下 WorkManager 的初始化过程。
在默认的情况下,WorkManager 并不是在我们调用 WorkManager.getInstance() 时创建的。通过反编译一下 apk,会发现在 AndroidManifest 文件中注册了名为 WorkManagerInitializer 的 ContentProvider。因此 WorkManager 在 app 冷启动的时候已经被创建。
//AndroidManifest.xml
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:exported="false"
android:multiprocess="true"
android:authorities="com.jandroid.multivideo.workmanager-init"
android:directBootAware="false" />
WorkManagerInitializer 的 onCreate() 方法:
//WorkManagerInitializer
public boolean onCreate() {
// Initialize WorkManager with the default configuration.
WorkManager.initialize(getContext(), new Configuration.Builder().build());
return true;
}
我们继续看 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<Scheduler> 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<Scheduler> 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 等,用来在适当的时机进行任务调度。再来看
//WorkManagerImpl
private void internalInit(@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
@NonNull WorkDatabase workDatabase,
@NonNull List<Scheduler> 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 的初始化流程就完成了。
WorkManager 的初始化是在 app 冷启动后,由 WorkManagerInitializer 这个 ContentProvider 执行的。
初始化过程包含了 Configuration,WorkManagerTaskExecutor,WorkDatabase,Schedulers,Processor 等的初始化过程。
Schedulers 有两个。
(1) GreedyScheduler: 执行没有任何约束的非周期性的任务。
(2) SystemJobScheduler/GcmBasedScheduler/SystemAlarmScheduler: 执行周期性或者有约束性的任务。优先返回 SystemJobScheduler,在 build version 小于 23 的情况下先尝试返回 GcmBasedScheduler,若返回为空再返回 SystemAlarmScheduler。
初始化的最后,会根据情况找到需要被执行的任务进行调度执行。
WorkManager 的初始化流程图:
WorkRequest 的创建是为了持有三个重要的成员变量。分别是:
WorkRequest 创建的流程图

在 WorkManager 执行了 enqueue() 后,创建 WorkContinuationImpl 对象执行 enqueue() 方法。
WorkContinuationImpl 持有的 EnqueueRunnable 对象将任务添加到 db,并交给 Schedulers 去调度。
Schedulers 将任务交给每一个 Scheduler 去处理。在我们的示例中,GreedyScheduler 会先处理这个任务。
GreedyScheduler 经过一系列判断后,调用 WorkManager 的 startWork() 方法执行这种一次性,非延迟,无约束的任务。
WorkManager 持有的 StartWorkRunnable 对象会将任务交给 Processor 去处理,执行 startWork() 方法。
Processor 创建一个 WorkerWrapper 对象,由它去调用 Worker 的 startWork() 方法,执行我们自定义 worker 的任务,并返回相应的 result。
任务完成后,WorkerWrapper 会根据 result 对任务状态,db 等进行更新,然后 schedule 下一个任务。
WorkManager 任务执行流程图:
SystemJobScheduler 使用的是 JobScheduler 来调度执行任务。由于 JobScheduler 的实现过程分析不在本文的讨论范围(总体是binder调用到SystemServer创建的JobSchedulerService进行处理),所以只看 WorkManager 是如何使用 JobScheduler 进行任务调度的。通常 JobScheduler 的使用步骤如下:
SystemAlarmScheduler 使用的是 AlarmManager 来调度执行任务。由于 AlarmManager 的实现过程分析不在本文的讨论范围(也是SystemServer创建的AlarmManagerService),所以只看 WorkManager 是如何使用 AlarmManager 进行任务调度的。反编译 apk 后,在 AndroidManifest 里有如下 receiver 注册:
WorkManager 的使用方法简单,但是在使用时还是要分清场景,适用于可延迟,周期性,必须执行完成的任务。通过对源码的分析,WorkManager 会针对不同 Android 版本的选择适当的策略。细致阅读代码,会发现针对指定的系统版本还有一些小的优化点。WorkManager 目前已经比较稳定,所以如果在场景适合的情况下,推荐使用 WorkManager 来代替原有的任务管理方案。