WorkManager解读
##一.官方定义:
1.简介:
使用 WorkManager API 可以轻松地调度即使在应用退出或设备重启时仍应运行的可延迟异步任务。它属于Android Jetpack的一部分。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O9bnIkMw-1587623472602)(/Users/tianchuangxin1/Library/Application Support/typora-user-images/image-20200108101944656.png)]
2.主要功能
- 最高向后兼容到 API 14
- 在运行 API 23 及以上级别的设备上使用 JobScheduler
- 在运行 API 14-22 的设备上结合使用 BroadcastReceiver 和 AlarmManager
- 添加网络可用性或充电状态等工作约束
- 调度一次性或周期性异步任务
- 监控和管理计划任务
- 将任务链接起来
- 确保任务执行,即使应用或设备重启也同样执行任务
- 遵循低电耗模式等省电功能
WorkManager 旨在用于可延迟运行(即不需要立即运行)并且在应用退出或设备重启时必须能够可靠运行的任务。目前经过测试得到的结果是,当把后台应用杀死后,任务停止运行(并不能保活进程)。
二.基本使用
worker的基本使用
###1.创建后台任务
/**
* TestWork简介
*
* @author tianchuangxin1
* @date 2020-01-02 18:11
*/
public class TestWork extends Worker {
public TestWork(
@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
//业务执行
//已成功完成构建
return Result.success();
//需要稍后重试
//return Result.retry();
//已失败
//return Result.failure();
}
}
2.配置运行任务方式和时间
//一次性任务
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(TestWork.class)
.addTag("a")
// .keepResultsForAtLeast()
// .
.build();
2.1定义任务运行条件
自定义工作请求常见用例:
- 处理网络可用性等任务约束
- 保证任务执行的延迟时间最短
- 处理任务重试和退避
- 处理任务输入和输出
- 使用标记对任务进行分组
2.1.1工作约束
Constraints ,指明工作何时可以运行(比如,设备接通电源,或者有网的情况)
//约束(如果指定多个约束,任务将需要满足所有约束才会运行)
Constraints constraints = new Constraints.Builder()
.setRequiresDeviceIdle(true)//指定{@link WorkRequest}运行时设备是否为空闲
.setRequiresCharging(true)//指定要运行的{@link WorkRequest}是否应该插入设备
.setRequiredNetworkType(NetworkType.NOT_ROAMING)
.setRequiresBatteryNotLow(true)//指定设备电池是否不应低于临界阈值
.setRequiresCharging(true)//网络状态
.setRequiresDeviceIdle(true)//指定{@link WorkRequest}运行时设备是否为空闲
.setRequiresStorageNotLow(true)//指定设备可用存储是否不应低于临界阈值
.addContentUriTrigger(myUri,false)//指定内容{@link android.net.Uri}时是否应该运行{@link WorkRequest}更新
.build();
//一次性任务
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(TestWork.class)
.setConstraints(constraints) //WorkRequest 中加入约束
.build();
2.1.2初始延迟
//任务加入执行队列后,至少10分钟之后才能执行(为啥是至少10分钟呢?)
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(TestWork.class)
// .setConstraints(constraints)
.setInitialDelay(10, TimeUnit.MINUTES)
.build();
2.1.3重试和退避政策
//odWork 中添加重试方法。那么在之后的重试中会按照规定的约束条件进行延迟退避执行
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(TestWork.class)
// .setConstraints(constraints)
// .setInitialDelay(10, TimeUnit.MINUTES)
.setBackoffCriteria(BackoffPolicy.LINEAR,100,TimeUnit.SECONDS) //LINEAR:退避延迟时间线型增长的方式;EXPONENTIAL:退避延迟时间指数型增长
.build();
2.1.4任务的输入/输出(类型)
//定义输入类型
Data data = new Data.Builder()
.putInt("result",0)
.build();
//一次性任务
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(TestWork.class)
// .setConstraints(constraints)
// .setInitialDelay(10, TimeUnit.MINUTES)
// .setBackoffCriteria(BackoffPolicy.LINEAR,100,TimeUnit.SECONDS) //LINEAR:退避延迟时间线型增长的方式;EXPONENTIAL:退避延迟时间指数型增长
.setInputData(data)
.build();
///
//doWork中获取对应值
count = getInputData().getInt("result",0);
//执行成功(返回结果)
Result.success(data)
2.1.5任务标记
//对任务添加标记(会按照标记进行分组),就可以对使用特定标记的所有任务执行操作。
//例如,WorkManager.cancelAllWorkByTag(String)
OneTimeWorkRequest cacheCleanupTask =
new OneTimeWorkRequest.Builder(UploadWork.class)
.setConstraints(constraints)
.addTag("test")
.build();
2.2其他用法
- 实时观察任务进度
- 获取任务执行的状态
- 实时更改work工作进度
主要是配合LiveData绑定数据,监听同步更新
3.任务添加/取消
//加入队列
WorkManager.getInstance(this).enqueue(uploadWorkRequest);
//取消所有work
WorkManager.getInstance(this).cancelAllWork();
//取消tag为test的所有任务
WorkManager.getInstance(this).cancelAllWorkByTag("test");
三、运行机制
UML图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X47aP0bs-1587623472606)(/Users/tianchuangxin1/Library/Application Support/typora-user-images/image-20200114155645461.png)]
针对类图中的内容,总结如下:
- Worker 类是一个抽象类,我们需要继承 Worker 类,并实现 doWork()方法,在 doWork()方法中实现我们需要在后台执行的业务逻辑,我们可以将业务封装在多个 Woker 的实现类中。
- WorkRequest 代表一个单独的后台任务。WorkRequest 类也是一个抽象类,我们通常会直接使用它的两个子类,OneTimeWorkRequest 和 PeriodicWorkRequest。
- WorkRequest 还有一个内部类 WorkRequest.Builder,OneTimeWorkRequest.Builder 和 PeriodicWorkRequest.Builder都是 WorkRequest.Builder 的子类,Builder 使用的是创建者模式,我们通过 Builder 实例来创建具体的 WorkRequest 对象。
- WorkRequest 可以指定那个 Worker 来执行任务。每一个 WorkRequest 实例都会生成唯一的id,可以通过 id 取消任务,或者获取任务的状态信息等。
- Constraints 类用来设定执行任务的条件,比如设备空闲时、充电时、电量充足时等等,通过 WorkRequest 的 setConstraints() 方法将 Constraints 对象传入。
- WorkInfo 用来记录任务信息,WorkInfo 有一个内部枚举State,用来保存任务的状态,一个后台任务有以下六种状态、分别是 ENQUEUED、RUNNING、SUCCEEDED、FAILED、BLOCKED 及 CANCELLED。
- 如果后台任务需要接收一些输入的参数数据,可以通过 Data 对象,Data.Builder 针对不同数据类型封装了一系列 putXXX()方法。后台任务执行后返回的结果,通过 Data 对象封装的一系列 getXXX()方法获取。
- WorkContinuation,很多 WorkManager 的高级用法都与这个类有关,比如建立任务链等,后面在 WorkManager 的高级用法中详细介绍。
- WorkManager,后台任务的调度器,它负责将我们创建好的 WorkRequest 对象添加到队列中,根据我们设定的约束条件(Constraints对象),并且会综合考虑设备资源的使用情况,进行任务的调度。
四、源码分析
##一、WorkManager的初始化
####1、WorkManager实例化(手动触发):
WorkManager.getInstance(this).enqueue(uploadWorkRequest);
进入getInstance看看WorkManager实例化
public static @NonNull WorkManager getInstance(@NonNull Context context) {
//WorkManager是抽象类,他的实现类是WorkManagerImpl
return WorkManagerImpl.getInstance(context);
}
进入WorkManagerImpl看它的实现
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static @NonNull WorkManagerImpl getInstance(@NonNull Context context) {
synchronized (sLock) {
//加锁,单例模式
WorkManagerImpl instance = getInstance();
if (instance == null) {// 为空
Context appContext = context.getApplicationContext();
if (appContext instanceof Configuration.Provider) {
//进行初始化
initialize(
appContext,
((Configuration.Provider) appContext).getWorkManagerConfiguration());
instance = getInstance(appContext);
} else {
throw new IllegalStateException("WorkManager is not initialized properly. You "
+ "have explicitly disabled WorkManagerInitializer in your manifest, "
+ "have not manually called WorkManager#initialize at this point, and "
+ "your Application does not implement Configuration.Provider.");
}
}
return instance;
}
}
initialize方法:
@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;
}
}
}
WorkManager基本实例化结束,这是我们手动调用的。
在应用进程被杀死后,重新打开应用,未执行完成的WorkReques或者排队状态的WorkRequest会重新开始执行。
###那这个时候WorkManager是怎么的启动初始化的呢?
解压APP,我们在AndroidManifest.xml文件中找到了一个provider的配置项。WorkManagerInitializer类又继承自ContentProvider,关于ContentProvider的启动过程不过多介绍,在应用的启动时候,会通过ActivityThread初始化ContentProvider(WorkManagerInitializer),即执行了onCreate方法完成了WorkManager的初始化。
@Override
public boolean onCreate() {
// Initialize WorkManager with the default configuration.
WorkManager.initialize(getContext(), new Configuration.Builder().build());
return true;
}
###初始化过程
initialize方法内部通过调用WorkManagerImpl的构造方法完成初始化任务。 (1)WorkDatabase创建数据库擦操作,内部使用的是Room框架。 (2)createSchedulers创建调度者集合。这里面主要有两种:GreedyScheduler和SystemJobScheduler(如果系统版本号大于23的话)。 (3)创建Processor类。
@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()));
//configuration、workTaskExecutor、database已经在前几次创建完成
//接下来才是重要的
//createSchedulers开始创建任务调度
List<Scheduler> schedulers = createSchedulers(applicationContext, workTaskExecutor);
//创建Processor 可以根据需要有计划的处理Work
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
//
internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}
createSchedulers方法会创建两种调度方式
@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.
//贪婪调度,指定直接执行,如果没有约束条件
new GreedyScheduler(context, taskExecutor, this));
}
Schedulers.createBestAvailableBackgroundScheduler(context, this)会根据api等级选择使用SystemJobScheduler或者SystemAlarmScheduler
@NonNull
static Scheduler createBestAvailableBackgroundScheduler(
@NonNull Context context,
@NonNull WorkManagerImpl workManager) {
Scheduler scheduler;
//判断api等级
if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
//>23使用JobScheduler
scheduler = new SystemJobScheduler(context, workManager);
setComponentEnabled(context, SystemJobService.class, true);
Logger.get().debug(TAG, "Created SystemJobScheduler and enabled SystemJobService");
} else {
//否则使用AlarmScheduler
scheduler = tryCreateGcmBasedScheduler(context);
if (scheduler == null) {
scheduler = new SystemAlarmScheduler(context);
setComponentEnabled(context, SystemAlarmService.class, true);
Logger.get().debug(TAG, "Created SystemAlarmScheduler");
}
}
return scheduler;
}
到这里WorkManagerImpl基本实例化完成。
###2.执行队列WorkManager.getInstance().enqueue()方法
WorkManager.getInstance返回的是WorkManagerImpl实例,所以我们进入到enqueue方法中看看。调用WorkContinuationImpl实例的enqueue方法。
@Override
@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.");
}
//实例化WorkContinuationImpl
return new WorkContinuationImpl(this, workRequests).enqueue();
}
调用WorkContinuationImpl实例的enqueue方法,直接进入WorkContinuationImpl.enqueue方法看看。
@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
EnqueueRunnable runnable = new EnqueueRunnable(this);
//getWorkTaskExecutor获取WorkManagerTaskExecutor对象,通过之前在Configuration创建的线程池中执行EnqueueRunnable任务
mWorkManagerImpl.getWorkTaskExecutor().executeOnBackgroundThread(runnable);
mOperation = runnable.getOperation();
} else {
Logger.get().warning(TAG,
String.format("Already enqueued work ids (%s)", TextUtils.join(", ", mIds)));
}
return mOperation;
}
EnqueueRunnable的run方法:
public EnqueueRunnable(@NonNull WorkContinuationImpl workContinuation) {
mWorkContinuation = workContinuation;
mOperation = new OperationImpl();
}
@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));
}
}
开始任务调度
/**
* Schedules work on the background scheduler.
*/
@VisibleForTesting
public void scheduleWorkInBackground() {
WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
//Schedulers类对安排的work进行选择出最优执行方案
Schedulers.schedule(
workManager.getConfiguration(),
workManager.getWorkDatabase(),
workManager.getSchedulers());
}
Schedulers类是控制调度的一个类,查看他的Schedulers.schedule方法:
public static void schedule(
@NonNull Configuration configuration,
@NonNull WorkDatabase workDatabase,
List<Scheduler> schedulers) {
if (schedulers == null || schedulers.size() == 0) {
return;
}
WorkSpecDao workSpecDao = workDatabase.workSpecDao();
List<WorkSpec> eligibleWorkSpecs;
//对需要进行调度执行的worker进行状态更新,挑选出适合合乎规则的worker
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();
}
//执行合乎规则的worker
if (eligibleWorkSpecs != null && eligibleWorkSpecs.size() > 0) {
WorkSpec[] eligibleWorkSpecsArray = eligibleWorkSpecs.toArray(new WorkSpec[0]);
// 调用初始化的scheduler
for (Scheduler scheduler : schedulers) {
scheduler.schedule(eligibleWorkSpecsArray);
}
}
}
从上面初始化的过程中,我们会创建两个Scheduler:GreedyScheduler和SystemJobScheduler,再查看这两个类中的schedule方法:
@VisibleForTesting
public void scheduleInternal(WorkSpec workSpec, int jobId) {
//WorkSpec转化为JobInfo(JobInfo是与SystemJobService绑定的)
JobInfo jobInfo = mSystemJobInfoConverter.convert(workSpec, jobId);
try {
//SystemJobService开始执行任务
mJobScheduler.schedule(jobInfo);
} catch (IllegalStateException e) {
// Rethrow a more verbose exception.
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);
}
}
@Override
public boolean onStartJob(@NonNull JobParameters params) {
if (mWorkManagerImpl == null) {
Logger.get().debug(TAG, "WorkManager is not initialized; requesting retry.");
jobFinished(params, true);
return false;
}
String workSpecId = getWorkSpecIdFromJobParameters(params);
if (TextUtils.isEmpty(workSpecId)) {
Logger.get().error(TAG, "WorkSpec id not found!");
return false;
}
synchronized (mJobParameters) {
if (mJobParameters.containsKey(workSpecId)) {
// This condition may happen due to our workaround for an undesired behavior in API
// 23. See the documentation in {@link SystemJobScheduler#schedule}.
Logger.get().debug(TAG, String.format(
"Job is already being executed by SystemJobService: %s", workSpecId));
return false;
}
mJobParameters.put(workSpecId, params);
}
WorkerParameters.RuntimeExtras runtimeExtras = null;
if (Build.VERSION.SDK_INT >= 24) {
runtimeExtras = new WorkerParameters.RuntimeExtras();
if (params.getTriggeredContentUris() != null) {
runtimeExtras.triggeredContentUris =
Arrays.asList(params.getTriggeredContentUris());
}
if (params.getTriggeredContentAuthorities() != null) {
runtimeExtras.triggeredContentAuthorities =
Arrays.asList(params.getTriggeredContentAuthorities());
}
if (Build.VERSION.SDK_INT >= 28) {
runtimeExtras.network = params.getNetwork();
}
}
//回到WorkManagerImpl调用startWork方法
mWorkManagerImpl.startWork(workSpecId, runtimeExtras);
return true;
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void startWork(
@NonNull String workSpecId,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
mWorkTaskExecutor
.executeOnBackgroundThread(
//分配到StartWorkRunnable执行
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
StartWorkRunnable是一个实现Runnable接口,run方法执行的是Processor类的startWork方法
@Override
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}
public boolean startWork(
@NonNull String id,
@Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
WorkerWrapper workWrapper;
synchronized (mLock) {
if (mEnqueuedWorkMap.containsKey(id)) {
return false;
}
//实例化了WorkWrapper
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);
}
//实例化的WorkWrapper加入了后台线程池WorkTaskExecutor
mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper);
Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id));
return true;
}
WorkWrapper也是一个实现Runnable接口的类,在其run方法调调用了Worker的startWork方法,至此整个流程结束:
@WorkerThread
@Override
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
mWorkDescription = createWorkDescription(mTags);
runWorker();
}
private void runWorker() {
//..........省略n行代码
mWorkTaskExecutor.getMainThreadExecutor()
.execute(new Runnable() {
@Override
public void run() {
try {
Logger.get().debug(TAG, String.format("Starting work for %s",
mWorkSpec.workerClassName));
//调用Worker的startWork方法
mInnerFuture = mWorker.startWork();
future.setFuture(mInnerFuture);
} catch (Throwable e) {
future.setException(e);
}
}
});
} else {
resolveIncorrectStatus();
}
}
@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 {
//调用doWork
Result result = doWork();
mFuture.set(result);
} catch (Throwable throwable) {
mFuture.setException(throwable);
}
}
});
return mFuture;
}
至此,我们从创建work 到把work添加到WorkRequest,在WorkManagerImpl实例化过程中,会创建完成数据库WorkDatabase.create,线程池的创建workTaskExecutor,任务调度集合List,执行者Processor。enqueue()方法会创建创建的EnqueueRunnable,在EnqueueRunnable的run方法中进行了Worker的数据库保存,然后执行scheduleWorkInBackground进行任务调度,当没有约束条件或者当前情况已经满足Worker执行,则会选择GreedyScheduler.schedule调度立即执行,如果有延迟任务或者一次性任务执行中断则会由SystemJobScheduler来执行,而SystemJobScheduler会把WorkSpec转为JobInfo,最终在SystemJobService中执行onStartJob方法,再调用WorkManagerImpl的startWork方法,startWork方法会在WorkRaskExcutor线程中添加实现了Runnable接口的StartWorkRunnable方法,StartWorkRunnable会接着调用Processor的额startWork方法,接着workWrapper实例化出来执行,最终在WorkWrapper中执行runWorker方法流程结束。
###那问题又来了,约束条件怎么触发,导致work的运行呢?
我们解压生成apk包,打开AndroidManifest.xml文件会发现有很多的约束的广播:
<receiver
android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryChargingProxy"
android:enabled="false"
android:exported="false"
android:directBootAware="false">
<intent-filter>
<action
android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action
android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
<receiver
android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryNotLowProxy"
android:enabled="false"
android:exported="false"
android:directBootAware="false">
<intent-filter>
<action
android:name="android.intent.action.BATTERY_OKAY" />
<action
android:name="android.intent.action.BATTERY_LOW" />
</intent-filter>
</receiver>
<receiver
android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$StorageNotLowProxy"
android:enabled="false"
android:exported="false"
android:directBootAware="false">
<intent-filter>
<action
android:name="android.intent.action.DEVICE_STORAGE_LOW" />
<action
android:name="android.intent.action.DEVICE_STORAGE_OK" />
</intent-filter>
</receiver>
<receiver
android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$NetworkStateProxy"
android:enabled="false"
android:exported="false"
android:directBootAware="false">
<intent-filter>
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<receiver
android:name="androidx.work.impl.background.systemalarm.RescheduleReceiver"
android:enabled="false"
android:exported="false"
android:directBootAware="false">
<intent-filter>
<action
android:name="android.intent.action.BOOT_COMPLETED" />
<action
android:name="android.intent.action.TIME_SET" />
<action
android:name="android.intent.action.TIMEZONE_CHANGED" />
</intent-filter>
</receiver>
<receiver
android:name="androidx.work.impl.background.systemalarm.ConstraintProxyUpdateReceiver"
android:enabled="@ref/0x7f030003"
android:exported="false"
android:directBootAware="false">
<intent-filter>
<action
android:name="androidx.work.impl.background.systemalarm.UpdateProxies" />
</intent-filter>
</receiver>
<service
android:name="androidx.room.MultiInstanceInvalidationService"
android:exported="false" />
</application>
</manifest>
ConstraintProxy类是广播,在收到通知的时候,会启动SystemAlarmService这个服务,其中ACTION 为ACTION_CONSTRAINTS_CHANGED
@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);
}
static Intent createConstraintsChangedIntent(@NonNull Context context) {
Intent intent = new Intent(context, SystemAlarmService.class);
intent.setAction(ACTION_CONSTRAINTS_CHANGED);
return intent;
}
SystemAlarmService类 内部调用mDispatcher.add方法
@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类 内部调用processCommand方法
@MainThread
public boolean add(@NonNull final Intent intent, final int startId) {
Logger.get().debug(TAG, String.format("Adding command %s (%s)", intent, startId));
assertMainThread();
//....省略n行代码
intent.putExtra(KEY_START_ID, startId);
synchronized (mIntents) {
boolean hasCommands = !mIntents.isEmpty();
mIntents.add(intent);
if (!hasCommands) {
//执行
processCommand();
}
}
return true;
}
@MainThread
@SuppressWarnings("FutureReturnValueIgnored")
private void processCommand() {
assertMainThread();
//....省略n行代码
try {
processCommandLock.acquire();
// Process commands on the background thread.
mWorkManager.getWorkTaskExecutor().executeOnBackgroundThread(new Runnable() {
@Override
public void run() {
//交由CommandHandler处理
mCommandHandler.onHandleIntent(mCurrentIntent, startId,
SystemAlarmDispatcher.this);
} catch (Throwable throwable) {
} finally {
wakeLock.release();
// Check if we have processed all commands
postOnMainThread(
new DequeueAndCheckForCompletion(SystemAlarmDispatcher.this));
}
}
}
});
} finally {
processCommandLock.release();
}
}
进行资源的重新调度
@WorkerThread
void onHandleIntent(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
String action = intent.getAction();
if (ACTION_CONSTRAINTS_CHANGED.equals(action)) {
//约束条件发生改变
handleConstraintsChanged(intent, startId, dispatcher);
} else if (ACTION_RESCHEDULE.equals(action)) {
//重新调度
handleReschedule(intent, startId, dispatcher);
} else {
Bundle extras = intent.getExtras();
if (!hasKeys(extras, KEY_WORKSPEC_ID)) {
Logger.get().error(TAG,
String.format("Invalid request for %s, requires %s.",
action,
KEY_WORKSPEC_ID));
} else {
if (ACTION_SCHEDULE_WORK.equals(action)) {
handleScheduleWorkIntent(intent, startId, dispatcher);
} else if (ACTION_DELAY_MET.equals(action)) {
//经过一系列的包装走到handleDelayMet
handleDelayMet(intent, startId, dispatcher);
} else if (ACTION_STOP_WORK.equals(action)) {
handleStopWork(intent, dispatcher);
} else if (ACTION_EXECUTION_COMPLETED.equals(action)) {
handleExecutionCompleted(intent, startId);
} else {
Logger.get().warning(TAG, String.format("Ignoring intent %s", intent));
}
}
}
}
onHandleIntent方法 onHandleIntent传入的Action 是ACTION_CONSTRAINTS_CHANGED。然后执行handleConstraintsChanged方法,在该方法内部经过一系列转化,会回到onHandleIntent方法中,而且ACTION为ACTION_DELAY_MET。DelayMetCommandHandler 经过成成调用,会调用到DelayMetCommandHandler类onAllConstraintsMet方法。在该方法内部会调用startWork方法。而startWork方法正式Processor的方法。又回到了上面分析的正常work的工作流程了。
private void handleDelayMet(
@NonNull Intent intent,
int startId,
@NonNull SystemAlarmDispatcher dispatcher) {
Bundle extras = intent.getExtras();
synchronized (mLock) {
String workSpecId = extras.getString(KEY_WORKSPEC_ID);
if (!mPendingDelayMet.containsKey(workSpecId)) {
DelayMetCommandHandler delayMetCommandHandler =
new DelayMetCommandHandler(mContext, startId, workSpecId, dispatcher);
mPendingDelayMet.put(workSpecId, delayMetCommandHandler);
//交由Process处理
delayMetCommandHandler.handleProcessWork();
} else {
}
}
}
实现原理就是通过监听各种约束条件变化的广播,然后经过层层转化,最终的处理逻辑和无限制条件的work流程一致。
####完结!感谢观看~