Android上有许多可延期的后台工作选项。此代码实验室涵盖WorkManager,这是一个可延迟的后台工作的兼容,灵活且简单的库。WorkManager是Android上推荐的任务调度框架,用于可延缓的工作,并且可以执行。
WorkManager是Android Jetpack的一部分,是用于后台工作的架构组件,需要兼顾机会和有保证的执行。机会性执行意味着WorkManager将尽快完成您的后台工作。有保证的执行意味着即使在离开应用程序的情况下,WorkManager也会兼顾各种情况下开始逻辑工作。
WorkManager是一个简单但非常灵活的库,它具有许多其他优点。这些包括:
即使用户离开特定屏幕或您的应用程序,WorkManager库对于完成有用的任务也是不错的选择。
可以很好地使用WorkManager的一些任务示例:
WorkManager提供有保证的执行,但并非所有任务都需要执行。因此,这不是将所有任务从主线程中运行掉的万能方法。有关何时使用WorkManager的更多详细信息,请参阅《后台处理指南》。
$ git clone -b java https://github.com/googlecodelabs/android-workmanager
WorkManager
需要下面的gradle依赖项。这些已包含在构建文件中:
dependencies {
// Other dependencies
implementation "androidx.work:work-runtime:$versions.work"
}
您应该work-runtime
从此处获取最新版本,然后输入正确的版本。目前,最新版本为:
versions.work = "2.3.3"
如果您将版本更新为较新的版本,请确保立即同步以将项目与更改的gradle文件同步。
您需要了解一些WorkManager类:
Worker
:在此处将要执行的实际工作的代码放在后台。您将扩展此类并重写doWork()
方法。WorkRequest
:这表示需要做一些工作。您将在Worker
创建的过程中将自己的信息传递给WorkRequest
。制作时,WorkRequest
您还可以指定类似Constraints
何时Worker
运行的内容。WorkManager
:此类实际上是安排您的WorkRequest
并使其运行。它以分散系统资源负载的方式调度WorkRequest
,同时遵守您指定的约束。import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import com.example.background.R;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
public class BlurWorker extends Worker {
public BlurWorker(
@NonNull Context appContext,
@NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
private static final String TAG = BlurWorker.class.getSimpleName();
@NonNull
@Override
public Result doWork() {
Context applicationContext = getApplicationContext();
try {
Bitmap picture = BitmapFactory.decodeResource(
applicationContext.getResources(),
R.drawable.test);
// Blur the bitmap
Bitmap output = WorkerUtils.blurBitmap(picture, applicationContext);
// Write bitmap to a temp file
Uri outputUri = WorkerUtils.writeBitmapToFile(applicationContext, output);
WorkerUtils.makeStatusNotification("Output is "
+ outputUri.toString(), applicationContext);
// If there were no errors, return SUCCESS
return Result.success();
} catch (Throwable throwable) {
// Technically WorkManager will return Result.failure()
// but it's best to be explicit about it.
// Thus if there were errors, we're return FAILURE
Log.e(TAG, "Error applying blur", throwable);
return Result.failure();
}
}
}
在中为WorkManager
实例创建变量,ViewModel
并在ViewModel
的构造函数中实例化该变量:
private WorkManager mWorkManager;
// BlurViewModel constructor
public BlurViewModel(@NonNull Application application) {
super(application);
mWorkManager = WorkManager.getInstance(application);
//...rest of the constructor
}
好了,是时候发出一个WorkRequest并告诉WorkManager运行它了。WorkRequest
s 有两种类型:
OneTimeWorkRequest:
WorkRequest
只会执行一次的A。PeriodicWorkRequest:
WorkRequest
一个周期将重复的A。我们只希望单击“ 转到”按钮时使图像模糊一次。单击“ applyBlur
执行”按钮时将调用该方法,因此请OneTimeWorkRequest
从BlurWorker
此处创建一个。然后,使用您的WorkManager
实例将您的WorkRequest.
将以下代码行添加到BlurViewModel
的applyBlur()方法中:
BlurViewModel.java
void applyBlur(int blurLevel) {
mWorkManager.enqueue(OneTimeWorkRequest.from(BlurWorker.class));
}
输入和输出通过Data
对象传入和传出。Data
对象是键/值对的轻量级容器。他们是为了存储小数据量,可能通过WorkRequest输入
和输出。
/**
* 创建包含Uri的输入数据
* @return Data类,包含Uri的字符串
*/
private Data createInputDataForUri() {
Data.Builder builder = new Data.Builder();
if (mImageUri != null) {
builder.putString(KEY_IMAGE_URI, mImageUri.toString());
}
return builder.build();
}
void applyBlur(int blurLevel) {
OneTimeWorkRequest blurRequest =
new OneTimeWorkRequest.Builder(BlurWorker.class)
.setInputData(createInputDataForUri())
.build();
mWorkManager.enqueue(blurRequest);
}
更新BlurWorker
的doWork()
方法,以获取从Data
对象传递来的URI :
public Result doWork() {
Context applicationContext = getApplicationContext();
// ADD THIS LINE
String resourceUri = getInputData().getString(Constants.KEY_IMAGE_URI);
//... rest of doWork()
}
我们已经完成了此Worker的工作,现在可以返回Result.success()
。我们将提供OutputURI作为输出数据。
Data outputData = new Data.Builder()
.putString(KEY_IMAGE_URI, outputUri.toString())
.build();
return Result.success(outputData);
WorkManager允许您创建独立的WorkerRequest
按顺序或并行运行。在这一步中,您将创建一个如下所示的工作链:
一个链接的输出WorkRequest
成为链接中下一链接的输入WorkRequest
。各个WorkRequest
彼此之间传递的输入和输出,并在上图中显示为蓝色部分的文本。
现在不是通过WorkManager.enqueue()来发送请求,而是调用WorkManager.beginWith(),它放回WorkContinuation类,用来定义工作请求链。
// Example code. Don't copy to the project
WorkContinuation continuation = mWorkManager.beginWith(workA);
continuation.then(workB) // FYI, then() returns a new WorkContinuation instance
.then(workC)
.enqueue(); // Enqueues the WorkContinuation which is a chain of work
如果您一次只希望运行一个工作链,您可以使用beginUniqueWork
代替beginWith
;
确保模糊文件的工作链是唯一的beginUniqueWork
。传递IMAGE_MANIPULATION_WORK_NAME
作为密钥。您还需要传递ExistingWorkPolicy
。你的选择是REPLACE
,KEEP
或者APPEND
。
WorkContinuation continuation = mWorkManager
.beginUniqueWork(IMAGE_MANIPULATION_WORK_NAME,
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequest.from(CleanupWorker.class));
您将使用标签来标记您的工作,而不是使用WorkManager ID
OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
.addTag(TAG_OUTPUT) // This adds the tag
.build();
// New instance variable for the WorkInfo class
private LiveData> mSavedWorkInfo;
// Placed this code in the BlurViewModel constructor
mSavedWorkInfo = mWorkManager.getWorkInfosByTagLiveData(TAG_OUTPUT);
// Add a getter method for mSavedWorkInfo
LiveData> getOutputWorkInfo() { return mSavedWorkInfo; }
使用以下workInfo.getState().isFinished()
检查工作状态是否已完成 ;
// Show work status, added in onCreate()
mViewModel.getOutputWorkInfo().observe(this, listOfWorkInfos -> {
// If there are no matching work info, do nothing
if (listOfWorkInfos == null || listOfWorkInfos.isEmpty()) {
return;
}
// We only care about the first output status.
// Every continuation has only one worker tagged TAG_OUTPUT
WorkInfo workInfo = listOfWorkInfos.get(0);
boolean finished = workInfo.getState().isFinished();
if (!finished) {
showWorkInProgress();
} else {
showWorkFinished();
}
});
您可以使用ID,标签和唯一链名取消工作。
void cancelWork() {
mWorkManager.cancelUniqueWork(IMAGE_MANIPULATION_WORK_NAME);
}