前言
由于笔者目前水平限制,表达能力有限,尽请见谅。
WorkManager 是 Android Jetpack 库的一部分,提供了一种向后兼容的方式来安排可延迟的异步任务,这些任务即使在应用退出或设备重启后也应该继续执行。它是 Android 推荐的解决方案,用于处理需要保证执行的后台任务。WorkManager 适合用于那些不需要立即执行的任务,但最终需要完成的任务。
前文主要介绍了调用getInstance获取WorkManager实例系统背后做了什么,本文将继续深入。
正文
WorkManagerInitializer
WorkManager
利用了Android系统在应用启动时自动初始化ContentProvider
的特性,来进行其自身的初始化过程,自动初始化是通过一个特殊的ContentProvider
实现的,名为WorkManagerInitializer。
开发者可以在AndroidManifest.xml
文件中声明这个ContentProvider声明这个
ContentProvider来实现应用启动时自动初始化:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
android:multiprocess="true">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup" />
</provider>
而 WorkManagerInitializer的实现如下:
可以发现,WorkManagerInitializer
类实现了androidx.startup.Initializer
接口,这使得它可以被Startup
库识别和调用。
dependencies
方法返回一个空列表,表示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();
}
}
至于上面代码调用的Configuration类,是一个kotlin编写的类,里面包含了各种各种WorkManager运行时的各种参数和行为。
自定义configuration代码如下,其源码不再深究
val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setExecutor(Executors.newFixedThreadPool(5))
.build()
WorkManager.initialize(context, config)
WorkContinuation
WorkContinuation
类是 WorkManager 库中的核心组件之一,用于创建和管理复杂的任务依赖关系。它允许开发者将多个 OneTimeWorkRequest
对象链接在一起,形成一个有向无环图(DAG)的任务流,这样可以确保某些工作在其他工作完成后才开始执行。
其可以实现如下复杂功能:
WorkContinuation left = workManager.beginWith(A).then(B);
WorkContinuation right = workManager.beginWith(C).then(D);
WorkContinuation finalContinuation = WorkContinuation.combine(Arrays.asList(left, right)).then(E);
finalContinuation.enqueue();
这离不开then(OneTimeWorkRequest work) 和 then(List<OneTimeWorkRequest> work)两个方法
public final @NonNull WorkContinuation then(@NonNull OneTimeWorkRequest work) {
return then(Collections.singletonList(work));
}
(下面这段代码在WorkManagerImpl类内,WorkManager类中此方法为抽象方法)
@Override
public @NonNull WorkContinuation then(@NonNull List<OneTimeWorkRequest> work) {
if (work.isEmpty()) {
return this;
} else {
return new WorkContinuationImpl(mWorkManagerImpl,
mName,
ExistingWorkPolicy.KEEP,
work,
Collections.singletonList(this));
}
}
这两个方法用于添加依赖于当前WorkContinuation中所有任务成功完成的一个或多个OneTimeWorkRequest
任务。then
方法返回一个新的WorkContinuation
实例,允许进一步的链式调用。
除此以外还有getWorkInfosLiveData() 和 getWorkInfos()这两个方法,用于查看工作链中所有工作请求状态的方式。getWorkInfosLiveData()
返回一个LiveData<List<WorkInfo>>
对象,允许应用组件观察工作状态的变化;getWorkInfos()
返回一个ListenableFuture<List<WorkInfo>>
,适用于需要异步获取工作状态的场景。
@Override
public @NonNull LiveData<List<WorkInfo>> getWorkInfosLiveData() {
return mWorkManagerImpl.getWorkInfosById(mAllIds);
}
@NonNull
@Override
public ListenableFuture<List<WorkInfo>> getWorkInfos() {
return StatusRunnable.forStringIds(mWorkManagerImpl.getWorkDatabase(),
mWorkManagerImpl.getWorkTaskExecutor(), mAllIds);
}
除此以外,还有hasCycles() 和 prerequisitesFor()用于检测工作链中是否存在循环依赖(死锁),递归遍历工作链和其父工作链,检查是否有工作请求的ID出现在其依赖路径中。
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
private static boolean hasCycles(
@NonNull WorkContinuationImpl continuation,
@NonNull Set<String> visited) {
// mark the ids of this workContinuation as visited
// before we check if the parents have cycles.
visited.addAll(continuation.getIds());
Set<String> prerequisiteIds = prerequisitesFor(continuation);
for (String id : visited) {
if (prerequisiteIds.contains(id)) {
// This prerequisite has already been visited before.
// There is a cycle.
return true;
}
}
List<WorkContinuationImpl> parents = continuation.getParents();
if (parents != null && !parents.isEmpty()) {
for (WorkContinuationImpl parent : parents) {
// if any of the parent has a cycle, then bail out
if (hasCycles(parent, visited)) {
return true;
}
}
}
// Un-mark the ids of the workContinuation as visited for the next parent.
// This is because we don't want to change the state of visited ids for subsequent parents
// This is being done to avoid allocations. Ideally we would check for a
// hasCycles(parent, new HashSet<>(visited)) instead.
visited.removeAll(continuation.getIds());
return false;
}
/**
* @return the {@link Set} of pre-requisites for a given {@link WorkContinuationImpl}.
*/
@NonNull
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static Set<String> prerequisitesFor(@NonNull WorkContinuationImpl continuation) {
Set<String> preRequisites = new HashSet<>();
List<WorkContinuationImpl> parents = continuation.getParents();
if (parents != null && !parents.isEmpty()) {
for (WorkContinuationImpl parent : parents) {
preRequisites.addAll(parent.getIds());
}
}
return preRequisites;
}
下篇文章仍旧会继续深入WorkManager的其他源码,加深对其的理解。