Defining your Work Requests
WorkRequest 是一个抽象类:它有2个直接子类:
- OneTimeWorkRequest (只执行一次)
from(List<Class<? extends ListenableWorker>> workerClasses)
from(Class<? extends ListenableWorker> workerClass)
- PeriodicWorkRequest(以一定频率执行)
Work constraints
You can add Constraints to your work to indicate when it can run(你可以添加工作执行的条件)
Constraints constraints = new Constraints.Builder()
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
.build();
OneTimeWorkRequest compressionWork =
new OneTimeWorkRequest.Builder(CompressWorker.class)
.setConstraints(constraints)
.build();
还有很多其他设置条件,挑重点说下:
- setRequiresCharging(boolean requiresCharging) // 是否需要充着电
- setRequiresBatteryNotLow(boolean requiresBatteryNotLow) // 是否不能低电量
- setRequiredNetworkType(NetworkType networkType) // 设置可以使用的网络类型
- setRequiresDeviceIdle(boolean requiresDeviceIdle) // 是否需要设备空闲时
- setRequiresStorageNotLow(boolean requiresStorageNotLow) // 是否需要内存充足时
- addContentUriTrigger(Uri uri, boolean triggerForDescendants) // 监听uri对应内容的变化
- 还有一些延时的方法
When multiple constraints are specified, your task will run only when all the constraints are met.(当有多个约束时,只有等所有条件都符合才会执行)
WorkRequest.Builder
一些重要的方法:
- addTag(String tag) 设置Tag,编组,方便对组做操作
- build()
- setBackoffCriteria(BackoffPolicy backoffPolicy, long backoffDelay, TimeUnit timeUnit) 设置回退策略(主要针对重试间隔,主要有BackoffPolicy.LINEAR[线性增长]和BackoffPolicy.EXPONENTIAL[指数增长])
- setBackoffCriteria(BackoffPolicy backoffPolicy, Duration duration)
- setConstraints(Constraints constraints) 设置约束条件
- setInitialDelay(Duration duration) 设置最小延迟
- setInitialDelay(long duration, TimeUnit timeUnit)
- setInputData(Data inputData) 设置请求参数,比如url等
已知直接子类:
- OneTimeWorkRequest.Builder
- PeriodicWorkRequest.Builder
Data imageData = new Data.Builder
.putString(Constants.KEY_IMAGE_URI, imageUriString)
.build();
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class)
.setInputData(imageData)
.build()
You can group your tasks logically by assigning a tag string to any WorkRequest object. This allows you to operate on all tasks with a particular tag.
OneTimeWorkRequest cacheCleanupTask =
new OneTimeWorkRequest.Builder(CacheCleanupWorker.class)
.setConstraints(constraints)
.addTag("cleanup")
.build();
The Worker class can access the input arguments by calling Worker.getInputData().(Worker可以通过getInputData(获取输入参数)
Similarily, the Data class can be used to output a return value. Return the Data object by including it in the Result on Result.success() or Result.failure(), as shown below.(同样Data可以用于包裹输出值,如下面实例,通过Result.success() or Result.failure()返回一个Result对象)
public class UploadWorker extends Worker {
public UploadWorker(
@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
}
@Override
public Result doWork() {
// Get the input
String imageUriInput = getInputData().getString(Constants.KEY_IMAGE_URI)
// TODO: validate inputs.
// Do the work
Response response = uploadFile(imageUriInput)
// Create the output of the work
Data outputData = new Data.Builder
.putString(Constants.KEY_IMAGE_URL, response.imageUrl)
.build();
// Return the output
return Result.success(outputData)
}
}
通过Tag给工作任务编组
OneTimeWorkRequest cacheCleanupTask =
new OneTimeWorkRequest.Builder(CacheCleanupWorker.class)
.setConstraints(constraints)
.addTag("cleanup")
.build();
Work States(工作任务的状态)
状态列表如下:
- BLOCKED ,if it has prerequisite work that hasn’t finished yet.(如果它的先决条件没有执行完)
- ENQUEUED,满足条件的工作任务会进入这个状态
- RUNNING , 当任务正在执行的时候,处于这个状态
- SUCCEEDED,任务执行成功会处于这个状态,只有OneTimeWorkRequest(单次执行任务)可以进入该状态
- FAILED , 当一个任务返回Result.failure()会进入该状态,值得注意的是,该状态手势一个终结状态,只有OneTimeWorkRequest可以进入该状态,并且它的所有依赖者都会被标记为FAILED
- CANCELLED , 当一个任务被取消的时候,进入该状态,所有依赖它的任务同样会被标记为CANCELLED
Observing your work
After you enqueue your work, WorkManager allows you to check on its status. This information is available in a WorkInfo object, which includes the id of the work, its tags, its current State, and any output data.(当你把工作任务放入工作队列中后,可以通过WorkManager来检查它的状态。工作状态可以通过WorkInfo来获取,WorkInfo 中包含任务的id,任务当前的状态,和任何输出的数据)
你可以通过以下三种方式获取WorkInfo :
- WorkManager.getWorkInfoById(UUID) or WorkManager.getWorkInfoByIdLiveData(UUID).
- WorkManager.getWorkInfosByTag(String) or WorkManager.getWorkInfosByTagLiveData(String).
- WorkManager.getWorkInfosForUniqueWork(String) or WorkManager.getWorkInfosForUniqueWorkLiveData(String)
使用LiveData的方式,你可以通过注册一个监听器来监听workInfo的变化。
WorkManager.getInstance().getWorkInfoByIdLiveData(uploadWorkRequest.getId())
.observe(lifecycleOwner, new Observer<WorkInfo>() {
@Override
public void onChanged(@Nullable WorkInfo workInfo) {
if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
displayMessage("Work finished!")
}
}
});
Chaining Work(把任务连接成链)
WorkManager allows you to create and enqueue a chain of work that specifies multiple dependent tasks, and defines what order they should run in. This is particularly useful when you need to run several tasks in a particular order.(通过WorkManager我们可以定义一组有依赖关系的任务的执行顺序,通常这在需要以特别的顺序执行任务时会很有用)
你可以通过WorkManager.beginWith(OneTimeWorkRequest) 或者 WorkManager.beginWith(List) 创建一个WorkContinuation对象。然后WorkContinuation对象可以通过WorkContinuation.then(OneTimeWorkRequest) 或者 WorkContinuation.then(List) 来设置自己的依赖项。WorkContinuation.then(…),又返回一个新的WorkContinuation。当你添加一个OneTimeWorkRequests集合时,这些请求是并行运行的。最后我们可以通过WorkContinuation.enqueue()把我们的工作链加入到工作队列。
WorkManager.getInstance()
// Candidates to run in parallel
.beginWith(Arrays.asList(filter1, filter2, filter3))
// Dependent work (only runs after all previous work in chain)
.then(compress)
.then(upload)
// Don't forget to enqueue()
.enqueue();
Cancelling and stopping work
如果你不再需要之前加入队列的任务,你可以取消它。最简单的方式是通过id
WorkManager.cancelWorkById(workRequest.getId());
WorkManager会检查任务的状态,如果任务已经结束了,什么都不会发生,否则,它的状态将会变为CANCELLED,任务将不会再执行。任何依赖该任务的任务都会被取消。
另外,如果任务正在运行,worker会会收到一个调用执行ListenableWorker.onStopped(),重写该方法,处理潜在的清除工作,例如:close db 或者文件。
当然我们也可以通过tag的方式,使用WorkManager.cancelAllWorkByTag(String)取消工作请求。所有标记为该tag的请求都会被取消。同时我们也可以唯一名字的方式,调用WorkManager.cancelUniqueWork(String)取消工作请求。
下面列举一些工作任务可能被停止的原因:
- 我们调用取消方法(例如:WorkManager.cancelWorkById(UUID))明确要求取消任务,
- 当我们向队列中添加任务时,明确设置ExistingWorkPolicy为REPLAC时,之前旧的请求会立马终止。
- 工作任务执行的条件不再满足时,
- 系统指示停止相关任务。这种情况可以发生在超过执行期限,请求被安排在晚些的时候重试。
Recurring work(重复执行任务)
Your application may at times require that certain tasks run periodically. For example, you may want to periodically backup your data, download fresh content in your app, or upload logs to a server.(我们也许需要周期性的执行某个任务,比如,周期性的备份数据、下载并刷新界面内容,或者周期性的上传日志到服务器)
Use the PeriodicWorkRequest for such tasks that need to execute periodically.(PeriodicWorkRequest可以很好地满足周期性执行某个任务的需求)
PeriodicWorkRequest不能不能加入任务链中。
Constraints constraints = new Constraints.Builder()
.setRequiresCharging(true)
.build();
PeriodicWorkRequest saveRequest =
new PeriodicWorkRequest.Builder(SaveImageFileWorker.class, 1, TimeUnit.HOURS)
.setConstraints(constraints)
.build();
WorkManager.getInstance()
.enqueue(saveRequest);
The repeat interval is defined as the minimum time between repetitions. The exact time that the worker is going to be executed depends on the constraints that you are using in your work request and on the optimizations done by the system.(重复的频率这里只是做为最小时间间隔,实际的时间依赖与执行条件),举个例子,上面的代码设置了需要充着电的条件,这里如果没有插着电源,即使到了一个小时,也不会执行。
Unique work(唯一的请求,这里主要是去重作用)
Unique work is a powerful concept that guarantees that you only have one chain of work with a particular name at a time. Unlike ids, unique names are human-readable and specified by the developer instead being auto-generated by WorkManager. Unlike tags, unique names are only associated with one chain of work.(请求的唯一性是一个很有用的概念,它确保了相同名字的任务链在同一时间只有一个。和id不同,唯一名字不是通过WorkManager自动生成的而是由开发者指定的方便阅读的字符串。和tag不同,唯一名字只能关联一个任务链。)
你可以通过调用WorkManager.enqueueUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest) 或者 WorkManager.enqueueUniquePeriodicWork(String, ExistingPeriodicWorkPolicy, PeriodicWorkRequest).创建一个唯一任务链。第一个参数是唯一名字,第二参数是冲突策略,指定名字冲突时,WorkManager应该如何处理。
- REPLACE , 取消已经存在的,添加保留新的
- KEEP ,保留原有的,忽略新来的
- APPEND ,将新来的追加到原有的后面(类似文件的追加),当原有的最后一个任务执行完,执行新来的的第一个任务。
最后,当我们需要创建一个唯一任务链时,可以调用WorkManager.beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest) 而不是beginWith()。
配置见下面(这里需要注意是arch,不要搞错):
dependencies {
def work_version = "1.0.1"
// (Java only)
implementation "android.arch.work:work-runtime:$work_version"
// Kotlin + coroutines
implementation "android.arch.work:work-runtime-ktx:$work_version"
// optional - RxJava2 support
implementation "android.arch.work:work-rxjava2:$work_version"
// optional - Test helpers
androidTestImplementation "android.arch.work:work-testing:$work_version"
}