目录

WorkManager之添加任务

[TOC]

前言

Jetpack中的WorkManager用于管理后台运行的任务,可替代原先由Service执行的后台任务。

使用

Gradle

gradle引入

1
implementation "androidx.work:work-runtime-ktx:$work_version"

Worker

实现Worker接口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class MyWork(
    var appContext: Context,
    var workerParams: WorkerParameters
): Worker(appContext, workerParams) {

    override fun doWork(): Result {
        // TODO:执行任务的详细内容
        
        /**
          * 返回执行结果
          * 执行成功:Result.success()
          * 执行失败:Result.failure()
          * 稍后重试:Result.retry()
          */
        return Result.success()
    }

}

WorkerRequest

运用Worker构造任务请求WorkRequest

1
2
3
4
5
6
/** 
  * WorkerRequest两种类型
  * OneTimeWorkRequest:一次性任务
  * PeriodicWorkRequest:周期性任务
  */
var myWorkRequest: OneTimeWorkRequest = OneTimeWorkRequestBuilder<MyWorker>().build()

WorkerManager

将任务添加到WorkerManager的队列中

1
2
// 获取WorkManager实例(单例模式),并将任务添加到WorkManager的队列中
WorkManager.getInstance(context).enqueue(myWorkRequest)

进入队列源码解析

我们解析“添加任务”过程的源码。

1
WorkManager.getInstance(context).enqueue(myWorkRequest)

获取WorkManager实例

WorkManager是一个抽象类,我们在获取WorkManager实例的时候获取到的是它的实现类WorkManagerImpl

1
2
3
4
5
6
// WorkManager.java

// WorkManager获取实例的方法
public static @NonNull WorkManager getInstance(@NonNull Context context) {
    return WorkManagerImpl.getInstance(context);
}

enqueue()添加任务请求

拿到实例后,我们将任务请求WorkRequest请求传入enqueue()方法,有两个主要的enqueue()方法:

  • WorkManager中实现的enqueue(@NonNull WorkRequest workRequest):用于添加一个任务请求。
  • WorkManagerImpl中实现的equeue(@NonNull List<? extends WorkRequest> workRequests):用于添加一组任务请求。

WorkManager中的enqueue()

1
2
3
4
5
6
7
8
9
// WorkManager
@NonNull
public final Operation enqueue(@NonNull WorkRequest workRequest) {
    // 调用了下面的enqueue(@NonNull List<? extends WorkRequest> requests)
    return enqueue(Collections.singletonList(workRequest));
}

@NonNull
public abstract Operation enqueue(@NonNull List<? extends WorkRequest> requests);

可见,即便是添加一个任务请求WorkRequest,这个任务请求依然会被转化为任务请求列表List<WorkRequest,实际上执行的依然是enqueue(@NonNull List<? extends WorkRequest> requests),而这个方法在WorkManagerImpl中被实现了。

WorkManagerImpl中的enqueue()

WorkManagerImpl中我们实现了enqueue(@NonNull List<? extends WorkRequest> requests),该方法执行了WorkContinuationImpl(即WorkContinuation的实现类)的enqueue()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// WorkManagerImpl.java
@Override
@NonNull
public Operation enqueue(
    @NonNull List<? extends WorkRequest> workRequests
) {

    ...
    return new WorkContinuationImpl(this, workRequests).enqueue();
}

WorkContinuation

我们并不清楚在WorkContinuation是什么,我们在WorkContinuation.java的头部注释看到这样的解释内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
/*
 * <pre>
 *     A       C
 *     |       |
 *     B       D
 *     |       |
 *     +-------+
 *         |
 *         E    </pre>
 *
 * you would write the following:
 *
 * <pre>
 * {@code
 *  WorkContinuation left = workManager.beginWith(A).then(B);
 *  WorkContinuation right = workManager.beginWith(C).then(D);
 *  WorkContinuation final = WorkContinuation.combine(Arrays.asList(left, right)).then(E);
 *  final.enqueue();}</pre>
 */

显而易见,WorkContinuation是用于任务排序用的。 在WorkManagerImpl中会首先构造WorkContinuation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 WorkContinuationImpl(
        @NonNull WorkManagerImpl workManagerImpl,
        @NonNull List<? extends WorkRequest> work) {
    this(
        workManagerImpl,
        null,
        ExistingWorkPolicy.KEEP,
        work, // 传入List<WorkRequest>
        null
    );
}

调用了以下构造方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
WorkContinuationImpl(
    @NonNull WorkManagerImpl workManagerImpl,
    String name,
    ExistingWorkPolicy existingWorkPolicy,
    @NonNull List<? extends WorkRequest> work,
    @Nullable List<WorkContinuationImpl> parents
) {
    mWorkManagerImpl = workManagerImpl;
    mName = name;
    mExistingWorkPolicy = existingWorkPolicy;
    // List<WorkRequest>最终被传入mWork
    mWork = work;
    mParents = parents;
    mIds = new ArrayList<>(mWork.size());
    mAllIds = new ArrayList<>();
    if (parents != null) {
        for (WorkContinuationImpl parent : parents) {
            mAllIds.addAll(parent.mAllIds);
        }
    }
    for (int i = 0; i < work.size(); i++) {
        String id = work.get(i).getStringId();
        mIds.add(id);
        mAllIds.add(id);
    }
}

我们传入的WorkRequest最终被传递到WorkContinuationmWork这个队列中。 构造完成后,执行WorkContinuation中的enqueue()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Override
public @NonNull Operation enqueue() {
    
    ...
    if(!mEnqueued) {
    EnqueueRunnable runnable = new EnqueueRunnable(this);
    mWorkManagerImpl
        .getWorkTaskExecutor()
        .executeOnBackgroundThread(runnable);
    mOperation = runnable.getOperation();
    } else {
        ...
    }
    return mOperation;
}

他调用了WorkManagerImpl中的任务执行器WorkTaskExecutor将我们传入的任务调到后台线程中执行。

1
2
3
mWorkManagerImpl
        .getWorkTaskExecutor()
        .executeOnBackgroundThread(runnable);

总结

  • Worker定义任务内容,WorkerRequest定义任务请求,WorkerManager管理任务的执行,WorkContinuation管理任务的顺序。
  • 无论是添加一个任务请求Workquest还是一组任务请求List<WorkRequest>,执行的都是WorkManagerImpl中添加一组任务请求的方法enqueue(@NonNull List<? extends WorkRequest> requests)
  • 任务最终会被WorkManagerImpl中的WorkTaskExecutor调用到后台线程中执行。

代码的主体逻辑如下: /workmanager%E4%B9%8B%E6%B7%BB%E5%8A%A0%E4%BB%BB%E5%8A%A1/WorkManager%E4%B9%8B%E6%B7%BB%E5%8A%A0%E4%BB%BB%E5%8A%A1.resources/7BD1ABA9-4B5B-4E0B-8E94-CF62BD6C9941.png