Q: 什么是WorkManager?
WorkManager 是一个 Android Jetpack 库,当满足工作的约束条件时,用来运行可延迟、需要保障的后台工作,即使应用程序退出,系统也会运行它们。
Q:WorkManager的适用场景?
1、可延迟进行的任务
a.满足某些条件才执行的任务,如需要在充电时才执行的任务。 b.用户无感知或可延迟感知的任务,如同步配置信息,同步资源,同步通讯录等。
2、定期重复性任务,但时效性要求不高的,如定期 log 上传,数据备份等。
3、退出应用后还应继续执行的未完成任务。
Q:WorkManager的好处?
- 处理不同系统版本的兼容性
- 遵循系统健康最佳实践
- 支持异步一次性和周期性任务
- 支持带输入/输出的链式任务
- 允许你设置在任务运行时的约束
- 即使应用程序或设备重启,也可以保证任务执行
Q:WorkManager的特点?
保证任务一定会被执行
WorkManager 有自己的数据库,每一个任务的信息与任务状态,都会保存在本地数据库中。所以即使程序没有在运行,或者在设备重启等情况下,WorkManager 依然可以保证任务的执行,只是不保证任务立即被执行。
合理使用设备资源
在执行很多周期性或非立即执行的任务时,WorkManager 提供我们 API,帮助我们合理利用设备资源,避免不必要的内存,流量,电量等消耗。
Q:WorkManager的初始化?
1、WorkManager 的初始化是在 app 冷启动后,由 WorkManagerInitializer 这个 ContentProvider 执行的。
2、初始化过程包含了 Configuration,WorkManagerTaskExecutor,WorkDatabase,Schedulers,Processor 等的初始化过程。
Schedulers 有两个。
(1) GreedyScheduler: 执行没有任何约束的非周期性的任务。
(2)SystemJobScheduler/GcmBasedScheduler/SystemAlarmScheduler: 执行周期性或者有约束性的任务。优先返回 SystemJobScheduler,在 build version 小于 23 的情况下先尝试返回 GcmBasedScheduler,若返回为空再返回 SystemAlarmScheduler。
3、初始化的最后,会根据情况找到需要被执行的任务进行调度执行。
Q: 不带约束条件的任务执行流程?
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 下一个任务。
Q:带约束条件的任务执行过程?
在任务执行的过程中,由于增加了约束条件,常驻的 GreedyScheduler 的 schedule() 方法将不会 startWork(),而是根据 build version 交由 SystemJobScheduler 或 SystemAlarmScheduler 进行处理。
SystemJobScheduler (Build Version >=23)
合理使用设备资源
>> 在执行很多周期性或非立即执行的任务时,WorkManager 提供我们 API,帮助我们合理利用设备资源,避免不必要的内存,流量,电量等消耗。
Q:WorkManager的初始化?
> 1、WorkManager 的初始化是在 app 冷启动后,由 WorkManagerInitializer 这个 ContentProvider 执行的。
>2、初始化过程包含了 Configuration,WorkManagerTaskExecutor,WorkDatabase,Schedulers,Processor 等的初始化过程。
Schedulers 有两个。
>(1) GreedyScheduler: 执行没有任何约束的非周期性的任务。
(2)SystemJobScheduler/GcmBasedScheduler/SystemAlarmScheduler: 执行周期性或者有约束性的任务。优先返回 SystemJobScheduler,在 build version 小于 23 的情况下先尝试返回 GcmBasedScheduler,若返回为空再返回 SystemAlarmScheduler。
>3、初始化的最后,会根据情况找到需要被执行的任务进行调度执行。
Q: 不带约束条件的任务执行流程?
>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 下一个任务。
Q:带约束条件的任务执行过程?
> 在任务执行的过程中,由于增加了约束条件,常驻的 GreedyScheduler 的 schedule() 方法将不会 startWork(),而是根据 build version 交由 SystemJobScheduler 或 SystemAlarmScheduler 进行处理。
>>SystemJobScheduler (Build Version >=23)
在SystemJobScheduler的构造函数中,会获取JobScheduler对象,并传入了一个SystemJobInfoConverter对象( 用来将我们的workSpecs转化为JobInfo,这个JobInfo是jobScheduler需要的参数 ,用来描述任务的执行时间,条件,策略等一系列的行为。),在SystemJobScheduler 的 schedule() 方法执行了 scheduleInternal();
JobScheduler是系统服务,由android程序启动的时候自动拉起无需手动去操作,而与JobScheduler对应的jobservice由系统自动生成,这里的JobService是SystemJobService,当JobScheduler中的条件满足时,SystemJobService就会被调用到。
在 SystemJobService中的onStartJob中,重点是最后一个方法,该方法调用了WorkManagerImpl.startWork。
SystemAlarmScheduler(Build Version < 23)
SystemAlarmScheduler 使用的是 AlarmManager 来调度执行任务。
在 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));
}
}
}
到这里终于看到由 SystemAlarmDispatcher 调用了 Processor 的 startWork() 方法,回到了之前章节分析的任务执行流程。到此为止,一个任务在不同条件下的创建,执行流程就分析完毕。
Q:WorkManager在设备重启后如何保证任务可以得到执行?
WorkManager在初始化时创建了Room数据库, 将任务列表序列化到本地,记录每一个任务的属性,执行条件,执行顺序及执行状态等。从而保证任务在冷启动或硬件重启后,可以根据条件继续执行。
WorkManager 流程分析和源码解析 | 开发者说·DTalk
](https://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652069060&idx=2&sn=77398948c657a70aeae4db35f8042a35&chksm=808cfc81b7fb759727b3b96d41addb3d6bb5f8793c064fb295631f0be496a4567ba75214dd3d&mpshare=1&scene=23&srcid=1107uIVkYdQ2fu0qgbADCEBW&sharer_sharetime=1604719995685&sharer_shareid=8206e3713102e9ca474649d51eda190c%23rd)
使用 WorkManager 处理需要立刻执行的后台任务