WorkManager 是 Jetpack 组件库的一个组件,负责管理后台任务。
WorkManager API 可以让你更加容易的管理一些后台任务,即使你的应用是退出或者设备重启的状态。
WorkManager 适用于任务的延迟执行,不需要立即执行,并且可以可靠的执行即使应用退出或者设备重启。例如:
向后端服务发送日志分析 定期与服务器同步应用程序数据WorkManager 不适用于那些在应用进程消失的时候,可以安全被终止的后台任务。
WorkManager和传统 Service 后台任务的区别: WorkManager不会因为应用进程的消失而被终止,即使设备被重启。而 Service 是做不到的。 Service 更加适用于应用内的后台任务。 WorkManager 可以设置延迟执行,不需要马上执行,也就是我们常说的定时任务。 二、WorkManager 核心类我们先来看看 WorkManager 相关的几个类:
Worker
任务的执行者,是一个抽象类,需要继承它实现要执行的任务。
WorkRequest
指定让哪个 Woker 执行任务,指定执行的环境,执行的顺序等。
要使用它的子类 OneTimeWorkRequest 或 PeriodicWorkRequest。
WorkManager
管理任务请求和任务队列,发起的 WorkRequest 会进入它的任务队列。
WorkStatus
包含有任务的状态和任务的信息,以 LiveData 的形式提供给观察者。
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);
}
@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()
{
@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()
{
@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 taskList = new ArrayList();
taskList.add(workContinuation1);
taskList.add(workContinuation2);
WorkContinuation.combine(taskList).then(WorkRequestE).enqueue();
作者:Fighting_初心