介绍
何时使用WorkManager
WorkManager最适用于可以延迟的任务,即使应用程序或设备重新启动(例如,使用后端服务定期同步数据并上载日志或分析数据),仍然可以运行。
向后兼容性
WorkManager将利用正确的调度API:它在Android 6.0+(API 23+)上使用JobScheduler API,在以前的版本上使用AlarmManager和BroadcastReceiver的组合。
例如,当系统处于打盹模式时,WorkManager将在Android 6.0+(API 23+)设备的维护窗口期间安排后台工作。
可靠的调度
使用WorkManager,可以轻松添加网络可用性或计费状态等约束。任务将在满足约束时运行,并在运行时失败时自动重试。例如,如果任务需要网络可用,则当网络不再可用时将停止该任务,并在以后重试。
不仅如此,它还可以使用LiveData监视工作状态并检索工作结果,这样可以在任务完成时通知您的UI。
-
Worker
指定需要执行的任务。WorkManager api包含一个抽象的Worker类。我们需要继承并实现这个类 -
WorkRequest
表示一个独立的任务。一个WorkRequest对象需要至少指定一个执行该任务的Worker类。当然我们也可以添加更多的细节,比如指定任务应该运行的环境等。每一个WorkRequest都有一个自动生成唯一ID,我们可以使用这个ID来执行诸如取消排队任务或者获取任务状态等操作。WorkRequest是一个抽象类,我们可以使用系统提供的子类-OneTimeWorkRequest 和 PeriodicWorkRequest -
WorkRequest.Builder:
创建WorkRequest对象的帮助类。同样,我们也需要用系统提供的子类:OneTimeWorkRequest.Builder 或者 PeriodicWorkRequest.Builder。 -
Constraints
指定任务运行的限制条件(例如,“仅当连接到网络时”)。使用Constraint.Builder来创建Constraints,并在创建WorkRequest之前把Constraints传给WorkRequest.Builder。 -
WorkManager
对工作请求进行管理。我们需要把WorkRequest对象传给WorkManager以便将任务编入队列。WorkManager以这样的方式调度任务,以分散系统资源的负载,同时满足我们指定的约束条件。 -
WorkStatus
包含特定任务的信息。WorkManager为每个WorkRequest对象提供一个LiveData。LiveData持有一个WorkStatus对象;通过观察这个LiveData,我们可以确定任务的当前状态,并在任务完成后获得返回值。
使用
现在完成一个demo,功能是先将一张图片进行模糊处理,然后存储到文件中,这里分成两个任务进行
模糊处理任务BlurWorker
public class BlurWorker extends Worker {
public BlurWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
@Override
public Worker.Result doWork() {
Context applicationContext = getApplicationContext();
// 增加时长 用于测试
WorkerUtils.sleep();
String resourceUri = getInputData().getString(Constants.KEY_IMAGE_URI);
try {
if (TextUtils.isEmpty(resourceUri)) {
Log.e(TAG, "Invalid input uri");
throw new IllegalArgumentException("Invalid input uri");
}
ContentResolver resolver = applicationContext.getContentResolver();
// Create a bitmap
Bitmap bitmap = BitmapFactory.decodeStream(
resolver.openInputStream(Uri.parse(resourceUri)));
// Blur the bitmap
Bitmap output = WorkerUtils.blurBitmap(bitmap, applicationContext);
// Write bitmap to a temp file
Uri outputUri = WorkerUtils.writeBitmapToFile(applicationContext, output);
// Return the output for the temp file
Data outputData = new Data.Builder().putString(
Constants.KEY_IMAGE_URI, outputUri.toString()).build();
return Result.success(outputData);
} catch (FileNotFoundException fileNotFoundException) {
throw new RuntimeException("Failed to decode input stream", fileNotFoundException);
} catch (Throwable throwable) {
// If there were errors, return FAILURE
Log.e(TAG, "Error applying blur", throwable);
return Result.failure();
}
}
}
存储到磁盘任务SaveImageToFileWorker
public class SaveImageToFileWorker extends Worker {
public SaveImageToFileWorker(
@NonNull Context appContext,
@NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
private static final String TITLE = "Blurred Image";
private static final SimpleDateFormat DATE_FORMATTER =
new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss z", Locale.getDefault());
@NonNull
@Override
public Worker.Result doWork() {
Context applicationContext = getApplicationContext();
ContentResolver resolver = applicationContext.getContentResolver();
try {
String resourceUri = getInputData()
.getString(Constants.KEY_IMAGE_URI);
Bitmap bitmap = BitmapFactory.decodeStream(
resolver.openInputStream(Uri.parse(resourceUri)));
// 存到文件
String imageUrl = MediaStore.Images.Media.insertImage(
resolver, bitmap, TITLE, DATE_FORMATTER.format(new Date()));
if (TextUtils.isEmpty(imageUrl)) {
return Result.failure();
}
// 输出数据
Data outputData = new Data.Builder()
.putString(Constants.KEY_IMAGE_URI, imageUrl)
.build();
return Result.success(outputData);
} catch (Exception exception) {
return Result.failure();
}
}
调用
// 模糊任务
OneTimeWorkRequest.Builder blurBuilder =
new OneTimeWorkRequest.Builder(BlurWorker.class);
// 设置输入数据
blurBuilder.setInputData(createInputDataForUri());
// 存贮任务
OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
.setConstraints(constraints)
.addTag(TAG_OUTPUT)
.build();
// Add WorkRequest to Cleanup temporary images
WorkContinuation continuation = mWorkManager
.beginUniqueWork(IMAGE_MANIPULATION_WORK_NAME,
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequest.from(CleanupWorker.class));
continuation = continuation.then(blurBuilder.build());
continuation = continuation.then(save);
// Actually start the work
continuation.enqueue();
取消任务
// 取消任务
UUID id = compressionWork.getId();
WorkManager.getInstance().cancelWorkById(id);
获取状态 和结果
LiveData<WorkInfo> status = WorkManager.getInstance().getWorkInfoByIdLiveData(compressionWork.getId());
status.observe(activity, new Observer<WorkInfo>() {
@Override
public void onChanged(@Nullable WorkInfo workInfo) {
// 获取状态
boolean finished = workInfo.getState().isFinished();
if (!finished) {
showWorkInProgress();
} else {
showWorkFinished();
// 获取输出内容
Data outputData = workInfo.getOutputData();
String outputImageUri =
outputData.getString(Constants.KEY_IMAGE_URI);
}
});
解析
下回揭晓…