Android源码阅读 WorkManager - 2

本文探讨了AndroidWorkManager的工作原理,重点关注其初始化过程通过ContentProvider自动进行,以及WorkContinuation如何管理任务依赖和避免循环。还介绍了如何自定义Configuration和使用WorkContinuation进行任务链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

由于笔者目前水平限制,表达能力有限,尽请见谅。

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的其他源码,加深对其的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏目艾拉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值