WorkManager是用于后台执行任务的工具,相比于Service、JobSchedule等,它拥有很低的能耗,但是它不是立即执行任务的,对于一些不需要及时完成的任务,使用WorkManager是一个很好的选择
WorkManager内部使用了数据库,所以能保证任务一定会执行。WorkManager的兼容性也很好,最低支持api14,api23以前,WorkManager内部是使用了JobSchedule,23以后使用的是AlarmManager BroadCastReceiver
使用WorkManager需要添加gradle依赖:
代码语言:javascript复制implementation 'androidx.work:work-runtime:2.5.0'
1.使用WorkManager
定义Work类,继承Worker,doWork方法需要返回一个Result的结果,有成功、重试、失败:
代码语言:javascript复制package com.aruba.workmanager;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
/**
* Created by aruba on 2021/9/15.
*/
public class MyWork extends Worker {
private static final String TAG = MyWork.class.getSimpleName();
public MyWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
Log.i(TAG,"doWork");
return Result.success();
}
}
在适当的地方,将任务入队:
代码语言:javascript复制 //设置条件
Constraints constraints = new Constraints.Builder()
//NetworkType.CONNECTED:需要有网络
//NetworkType.NOT_REQUIRED:不需要网络
//NetworkType.NOT_ROAMING:非漫游网络
//NetworkType.METERED:计费网络下执行(流量)
//NetworkType.UNMETERED:不计费网络(wifi)
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
// .setRequiresBatteryNotLow(true)//不在低电量
// .setRequiresCharging(true)//充电时执行
// .setRequiresStorageNotLow(true)//不在低存储空间
// .setRequiresDeviceIdle(true)//不在待机 api23
.build();
//配置任务
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWork.class)
.setConstraints(constraints)
//设置延迟
.setInitialDelay(5, TimeUnit.SECONDS)
.build();
//任务入队
WorkManager.getInstance(this).enqueue(workRequest);
2.指数退避策略
我们也可以为任务配置指数退避策略,当任务需要retry时,它会根据给定的退避时间指数增长,列如:退避时间为2,重试的时间间隔为:2,4,8...
代码语言:javascript复制 //配置任务
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWork.class)
.setConstraints(constraints)
//设置延迟
.setInitialDelay(5, TimeUnit.SECONDS)
//指数退避策略
.setBackoffCriteria(BackoffPolicy.LINEAR,2,TimeUnit.SECONDS)
.build();
3.为任务配置TAG
代码语言:javascript复制 //配置任务
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWork.class)
.setConstraints(constraints)
//设置延迟
.setInitialDelay(5, TimeUnit.SECONDS)
//指数退避策略
.setBackoffCriteria(BackoffPolicy.LINEAR,2,TimeUnit.SECONDS)
//设置tag
.addTag("work1")
.build();
4.监听任务状态
使用workManager对任务状态进行监听
代码语言:javascript复制 //添加任务监听
workManager.getWorkInfoByIdLiveData(workRequest.getId()).observe(this, new Observer<WorkInfo>() {
@Override
public void onChanged(WorkInfo workInfo) {
Log.i("WorkInfo", workInfo.toString());
}
});
5.取消任务
代码语言:javascript复制 //取消任务
workManager.cancelWorkById(workRequest.getId());
6.参数传递
参数传递分成两方面,一个是创建任务时传入参数,一个是执行任务时传递参数 使用Data在创建任务时传入参数:
代码语言:javascript复制 //传入参数
Data data = new Data.Builder()
.putString("createTask", "createTask")
.build();
//配置任务
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWork.class)
.setConstraints(constraints)
//设置延迟
.setInitialDelay(5, TimeUnit.SECONDS)
//指数退避策略
.setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.SECONDS)
//设置tag
.addTag("work1")
//传入参数
.setInputData(data)
.build();
在我们自定义的Work中,doWork方法内可以获取到创建时传递的参数,并且传递新的参数
代码语言:javascript复制 @NonNull
@Override
public Result doWork() {
Log.i(TAG,"doWork");
//获取参数
String createTask = getInputData().getString("createTask");
Log.i(TAG,"createTask");
//传递新参数
Data data = new Data.Builder()
.putString("doWork", "doWork complete")
.build();
return Result.success(data);
}
可以在监听任务状态时,获取完成任务的参数:
代码语言:javascript复制 //添加任务监听
workManager.getWorkInfoByIdLiveData(workRequest.getId()).observe(this, new Observer<WorkInfo>() {
@Override
public void onChanged(WorkInfo workInfo) {
Log.i("WorkInfo", workInfo.toString());
if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) {
String doWork = workInfo.getOutputData().getString("doWork");
Log.i("WorkInfo", doWork);
}
}
});
7.周期性任务
使用PeriodicWorkRequest对象,并且指定的时间不能低于15分钟
代码语言:javascript复制 //周期性任务
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest
.Builder(MyWork.class, Duration.ofMinutes(15))
.build();
}
8.任务链与任务组合
任务也是可以链式执行的:
代码语言:javascript复制 OneTimeWorkRequest aWork = new OneTimeWorkRequest.Builder(AWork.class)
.build();
OneTimeWorkRequest bWork = new OneTimeWorkRequest.Builder(BWork.class)
.build();
//先执行A再执行B
workManager.beginWith(aWork).then(bWork).enqueue();
任务组合,使用WorkContinuation的combine方法来组合WorkContinuation集合执行,可以使用then方法指定延后执行的任务:
代码语言:javascript复制 OneTimeWorkRequest aWork = new OneTimeWorkRequest.Builder(AWork.class)
.build();
OneTimeWorkRequest bWork = new OneTimeWorkRequest.Builder(BWork.class)
.build();
OneTimeWorkRequest cWork = new OneTimeWorkRequest.Builder(CWork.class)
.build();
OneTimeWorkRequest dWork = new OneTimeWorkRequest.Builder(DWork.class)
.build();
OneTimeWorkRequest eWork = new OneTimeWorkRequest.Builder(EWork.class)
.build();
//先A再B
WorkContinuation workContinuation1 = workManager.beginWith(aWork).then(bWork);
//先C再D
WorkContinuation workContinuation2 = workManager.beginWith(cWork).then(dWork);
List<WorkContinuation> workContinuations = new ArrayList<>();
workContinuations.add(workContinuation1);
workContinuations.add(workContinuation2);
//最后执行E
WorkContinuation.combine(workContinuations).then(eWork).enqueue();