Android Jetpack(八)WorkManager

一、WorkManager 介绍

        WorkManager 是 Jetpack 组件库的一个组件,负责管理后台任务

        WorkManager API 可以让你更加容易的管理一些后台任务,即使你的应用是退出或者设备重启的状态

        WorkManager 适用于任务的延迟执行,不需要立即执行,并且可以可靠的执行即使应用退出或者设备重启例如:

  • 向后端服务发送日志分析
  • 定期与服务器同步应用程序数据

        WorkManager 不适用于那些在应用进程消失的时候,可以安全被终止的后台任务

      WorkManager和传统 Service 后台任务的区别:

  • WorkManager不会因为应用进程的消失而被终止,即使设备被重启。而 Service 是做不到的。
  • Service 更加适用于应用内的后台任务。
  • WorkManager 可以设置延迟执行,不需要马上执行,也就是我们常说的定时任务。

二、WorkManager 核心类

        我们先来看看 WorkManager 相关的几个类:

  • Worker
    任务的执行者,是一个抽象类,需要继承它实现要执行的任务。

  • WorkRequest
    指定让哪个 Woker 执行任务,指定执行的环境,执行的顺序等。
    要使用它的子类 OneTimeWorkRequest PeriodicWorkRequest

  • WorkManager
    管理任务请求和任务队列,发起的 WorkRequest 会进入它的任务队列。

  • WorkStatus
    包含有任务的状态和任务的信息,以 LiveData 的形式提供给观察者。

三、WorkManager 使用

1. 导入依赖库

implementation "android.arch.work:work-runtime:1.0.1"

2. 使用 Worker 定义任务

public class UploadLogWorker extends Worker {
    private static final String TAG = "UploadLogWorker";

    public UploadLogWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    /**
     * 处理耗时任务
     * @return Result
     */
    @NonNull
    @Override
    public Result doWork() {
        Log.d(TAG, "doWork()");
        return Result.success();
    }
}

        doWork()方法有三种类型的返回值:

  • 执行成功返回Result.success()
  • 执行失败返回Result.failure()
  • 需要重新执行返回Result.retry()

3. 使用 WorkRequest 配置任务

        通过 WorkRequest 配置我们的任务何时运行以及如何运行

(1)通过 Constraints 设置任务触发条件

        例如,我们可以设置在设备处于充电,网络已连接,且电池电量充足的状态下,才出发我们设置的任务。

Constraints constraints = new Constraints.Builder()
        .setRequiresCharging(true)
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresBatteryNotLow(true)
        .build();

(2)将该 Constraints 设置到 WorkRequest

        WorkRequest 是一个抽象类,它有两种实现:

  • OneTimeWorkRequest:一次性任务 
  • PeriodicWorkRequest:周期性任务

        WorkRequest 还可以设置延迟执行任务。假设你没有设置触发条件,或者当你设置的触发条件符合系统的执行要求,此时,系统有可能立刻执行该任务,但如果你希望能够延迟执行,那么可以通过 setInitialDelay() 方法,延后任务的执行。

       WorkRequest 还可以设置指数退避策略。假如 Worker 线程的执行出现了异常,比如服务器宕机,那么你可能希望过一段时间,重试该任务。那么你可以在 Worker 的 doWork() 方法中返回 Result.retry(),系统会有默认的指数退避策略来帮你重试任务,你也可以通过 setBackoffCriteria() 方法,自定义指数退避策略。

OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadLogWorker.class)
        .setConstraints(constraints)//设置触发条件
        .setInitialDelay(10, TimeUnit.SECONDS)  //符合触发条件后,延迟10秒执行
        .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)//设置指数退避算法
        .addTag("UploadTag")  //设置Tag
        .build();

 (3)通过 WorkManager 执行任务

WorkManager.getInstance().enqueue(uploadWorkRequest);

        取消任务:

        与观察任务类似的,我们也可以根据Id或者Tag取消某个任务,或者取消所有任务。

WorkManager.getInstance(MainActivity.this).cancelAllWork();

四、WorkManager 拓展

1. 观察任务的状态

        任务在提交给系统后,通过 WorkInfo 获知任务的状态,WorkInfo 包含了任务的 id,tag,以及 Worker 对象传递过来的outputData,以及任务当前的状态。

        有三种方式可以得到 WorkInfo 对象

  • WorkManager.getWorkInfosByTag()
  • WorkManager.getWorkInfoById()
  • WorkManager.getWorkInfosForUniqueWork()

        如果你希望能够实时获知任务的状态。这三个方法还有对应的LiveData方法。

  • WorkManager.getWorkInfosByTagLiveData()
  • WorkManager.getWorkInfoByIdLiveData()
  • WorkManager.getWorkInfosForUniqueWorkLiveData()

        通过 LiveData,我们便可以在任务状态发生变化的时候,收到通知。 

WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.getId()).observe(MainActivity.this, new Observer<WorkInfo>()
{
    @Override
    public void onChanged(WorkInfo workInfo)
    {
        Log.d("onChanged()->", "workInfo:"+workInfo);
    }
});

 2. 传递数据

        WorkManager 和 Worker 之间的数据传递通过 Data 对象来完成。

        WorkManager 通过 setInputData() 方法向 Worker 传递数据。

Data inputData = new Data.Builder().putString("input_data", "Hello World!").build();

OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadLogWorker.class)
                .setInputData(inputData)
                .build();

        Worker 中接收数据,并在任务执行完成后,向 WorkManager 传递数据。

@Override
public Result doWork()
{
    //接收外面传递进来的数据
    String inputData = getInputData().getString("input_data");

    // 任务执行完成后返回数据
    Data outputData = new Data.Builder().putString("output_data", "Task Success!").build();

    return Result.success(outputData);
}

        WorkManager 通过 LiveData 的 WorkInfo.getOutputData(),得到从 Worker 传递过来的数据。

WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.getId()).observe(MainActivity.this, new Observer<WorkInfo>()
{
    @Override
    public void onChanged(WorkInfo workInfo)
    {
        if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED)
        {
            String outputData = workInfo.getOutputData().getString("output_data");
        }
    }
});
  注意:  Data只能用于传递一些小的基本类型数据,且数据最大不能超过10kb。

3. 周期任务

        周期性任务 PeriodicWorkRequest 会按照设定的时间定期执行。与 OneTimeWorkRequest 相比,二者使用起来没有太大差别。

        需要注意的是:周期性任务的间隔时间不能小于15分钟

PeriodicWorkRequest uploadWorkRequest = new PeriodicWorkRequest.Builder(UploadLogWorker.class, 15, TimeUnit.MINUTES)
        .setConstraints(constraints)
        .addTag(TAG)
        .build();

4. 任务链

        如果你有一系列的任务需要顺序执行,那么可以利用 WorkManager.beginWith().then().then()...enqueue() 方法。例如:我们在上传数据之前,需要先对数据进行压缩。

WorkManager.getInstance(this).beginWith(compressWorkRequest).then(uploadWorkRequest).enqueue();

        假设有更复杂的任务链,你还可以考虑使用 WorkContinuation.combine() 方法,将任务链组合起来。

WorkContinuation workContinuation1 =  WorkManager.getInstance(this).beginWith(WorkRequestA).then(WorkRequestB);
WorkContinuation workContinuation2 =  WorkManager.getInstance(this).beginWith(WorkRequestC).then(WorkRequestD);
List<WorkContinuation> taskList = new ArrayList<>();
taskList.add(workContinuation1);
taskList.add(workContinuation2);
WorkContinuation.combine(taskList).then(WorkRequestE).enqueue();
发布了67 篇原创文章 · 获赞 69 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_34519487/article/details/104340128