以下代码是用Java语言编写的,也并没有兼容AndroidX,如果项目兼容AndroidX的话,WorkManager实例的获取是有点区别的,Kotlin就可以去官网了,大概原理差不多,以下资料来源于官网文档,正好先用到一点,当做笔记记录一下。
用途、优点、添加依赖、用法思路
创建后台任务类、配置WorkManager请求参数以及执行
定义任务约束、任务延迟执行
定义任务的输入和输出、为任务添加标签、取消任务
后台任务状态的监听
设定一次只能激活一个特定名称的后台任务
属于JetPack结构组件,用于进行后台任务
操作简单,稳定性强,对于异步任务,即使APP退出运行或者设备重启,都能很好的保证任务的顺利执行
implementation "android.arch.work:work-runtime:1.0.1" (Java)
新建一个类继承Woker,并实现其方法,在其doWork()方法中进行后台任务,然后再根据返回的状态对任务结果进行相应的处理
Class DemoWorker extends Worker {
public DemoWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
}
@NonNull
@Override
public Result doWork() {
//在这里进行后台任务
return Result.success(); //此处返回值下面讲述
}
doWork()方法的返回值
Result.success():已成功完成
Result.failure() : 已失败文
Result.retry():稍后重试
构建一次性任务(只执行一次,执行完就自动结束)
/**
* OneTimeWorkRequest : 专门用于构建一次性任务
* DemoWorker: 指的是当前创建的后台任务类名称
*/
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(DemoWorker.class).build();
构建周期性任务(只隔一个周期执行一次,执行完就自动结束,周期间隔至少为15分钟)
/**
* PeriodicWorkRequest : 专门用于构建周期性任务
* 15 :计数单位
* TimeUnit.MINUTES : 以分钟为计时单位
* DemoWorker: 指的是当前创建的后台任务类名称
*/
PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(DeviceSyncWorker.class, 15, TimeUnit.MINUTES)
.build();
执行任务:(通过enqueue方法执行任务)
WorkManager.getInstance().enqueue(request);
添加约束:网络连接
Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
然后将constraints加入任务构建中,例如:
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(DemoWorker.class)
.setConstraints(constraints)
.build();
约束的种类:
addContentUriTrigger:
setRequiredNetworkType:网络连接状态约束(需要网络,不需要网络,不限时的网络,非漫游网络,计量网络连接)
setRequiresBatteryNotLow:设备电池电量处于可接受的水平才可以执行任务
setRequiresCharging:设备充电时才可以执行任务
setRequiresDeviceIdle:设备空闲状态时才可以执行任务
setRequiresStorageNotLow:设备存储处于可接受的范围才可以执行任务
setTriggerContentMaxDelay:设置从第一次检测到内容更改到计划的时间所允许的最大延迟
setTriggerContentUpdateDelay:设置从第一次检测到内容更改到计划的时间所允许的延迟
如果不希望任务立即执行,则可以将任务指定为在经过最短的初始延迟后启动,例如:
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(DemoWorker.class)
.setInitialDelay(10, TimeUnit.MINUTES)
.build();
使用场景:任务需要数据以传入参数的形式传入,或者将数据返回为结果(
注意:Data 对象应该很小,值可以是字符串、基元类型或数组变体。
如果需要将更多数据传入和传出工作器,应该将数据放在其他位置,例如 Room 数据库。Data 对象的大小上限为 10KB。
例如:(此处是官方的例子)
场景是:后台任务是处理图像上传,要求以要上传图片的URL为输入,并且要求用已上传图像的网址作为输出
代码如下:
/**
* Constants.KEY_IMAGE_URI :自定义的字符串常量
* imageUriString:要上传的图片URL
* UploadWorker:后台任务类的名称
*/
Data imageData = new Data.Builder
.putString(Constants.KEY_IMAGE_URI, imageUriString)
.build();
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class)
.setInputData(imageData)
.build()
输入的Data数据可在doWork()方法中进行获取,例如:
@NonNull
@Override
public Result doWork() {
String dataInput = getInputData().getString(Constants.KEY_IMAGE_URI);
//后台任务返回数据 uploadFile(dataInput)====>>> 后台任务
举例: Response response = uploadFile(dataInput)
//将后台任务返回的数据中取出要返回的数据,放入Data中
Data outputData = new Data.Builder
.putString(Constants.KEY_IMAGE_URI, response.imageUrl)
.build();
return Result.success(outputData);
}
添加标签的好处:通过标签来取消后台任务请求(可以将同一标签下所有的后台任务请求全部取消)
例如:
添加标签:
OneTimeWorkRequest cacheCleanupTask = new OneTimeWorkRequest.Builder(DemoWorker.class)
.setConstraints(constraints)
.addTag("cleanup")
.build();
通过标签取消任务:
WorkManager.getInstance().cancelAllWorkByTag("cleanup");
通过ID取消指定单个任务:
WorkManager.getInstance().cancelWorkById(request.id);
通过标签取消标签名下的所有任务:
WorkManager.getInstance().cancelAllWorkByTag("cleanup");
一次性取消全部任务:
WorkManager.getInstance().cancelAllWork();
通过id监听单个后台任务请求的运行结果:
WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(uploadWorkRequest.getId())
.observe(lifecycleOwner, new Observer() {
@Override
public void onChanged(@Nullable WorkInfo workInfo) {
if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
Log.e(TAG,"Success");
}
}
});
通过Tag标签监听同一标签下所有后台任务请求的运行结果:
WorkManager.getInstance().getWorkInfosByTagLiveData("tag").observe(this, new android.arch.lifecycle.Observer>() {
@Override
public void onChanged(@Nullable List workInfos) {
for (WorkInfo workInfo : workInfos) {
if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) {
Log.e(TAG,"Success");
}
}
}
});
如果后台任务执行是通过enqueueUniqueWork(“workName")执行的,可以通过getWorkInfosForUniqueWorkLiveData监听后台任务运行结果:
WorkManager.getInstance().getWorkInfosForUniqueWorkLiveData("workName").observe(this, new android.arch.lifecycle.Observer>() {
@Override
public void onChanged(@Nullable List workInfos) {
if (workInfos == null) {
Log.e(TAG,"Success");
return;
}
for (WorkInfo workInfo : workInfos) {
if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) {
Log.e(TAG,"Success");
}
}
}
});
/**
* enqueueUniqueWork:通过此方法设定一次只能激活一个特定名称的后台任务
* singleWork:进行此操作的唯一名称,之后状态监听要获取此名称
* ExistingWorkPolicy:工作策略(REPLACE:取消现有的序列并用新序列替换 KEEP:保持现有顺序并忽略新的请求
APPEND:将新序列附加到现有学列,在现有序列的最后一个任务完成后运行新序列的第一个任务)
* request:自行构建的一次性任务或者周期性任务
* 如何监听此任务状态,上述有代码
*/
WorkManager.getInstance().enqueueUniqueWork("singleWork", ExistingWorkPolicy.KEEP, request);
注意:WorkerManager要求必须在前一个后台任务运行成功后,下一个后台任务才会运行,也就是说,如果某个后台任务运行失败,或者被取消了,那么接下来的后台任务就都得不到运行了。
比如我们有A,B,C三个任务,我们需要顺序执行。那我们就可以
使用beginWith()方法用于开启一个链式任务(任务允许重复),后面接上后台任务,可使用then()方法链接即可;
WorkManager.getInstance().beginWith(A).then(B).then(C).enqueue();
使用beginUniqueWork()方法用于开启一个链式任务(任务不允许重复)
WorkManager.getInstance().beginUniqueWork("unique", ExistingWorkPolicy.KEEP, requestA)
.then(requestB)
.then(requestC)
.enqueue();
beginWith(),beginUniqueWork()两个函数开启的队列的唯一区别在于,队列里面的任务能不能重复。
beginWith()开始的队列里面的任务是可以重复的,beginUniqueWork()开始的队列里面的任务是不能重复的。
如果小伙伴发现书写中出现错误,或者有更好的封装办法,欢迎留言和私信。