介绍
WorkManager 旨在用于可延迟运行(即不需要立即运行)并且在应用退出或设备重启时必须能够可靠运行的任务。例如:
- 向后端服务发送日志或分析数据
- 定期将应用数据与服务器同步
步骤
将 WorkManager 添加到您的 Android 项目中
将以下依赖项添加到应用的
build.gradle
文件:
dependencies {
def work_version = "2.4.0"
// (Java only)
implementation "androidx.work:work-runtime:$work_version"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"
// optional - RxJava2 support
implementation "androidx.work:work-rxjava2:$work_version"
// optional - GCMNetworkManager support
implementation "androidx.work:work-gcm:$work_version"
// optional - Test helpers
androidTestImplementation "androidx.work:work-testing:$work_version"
}
2.创建后台任务Worker
class DialogAppraiseTipsWorker(val context: Context, parms: WorkerParameters) : Worker(context, parms) {
override fun doWork(): Result {
return if (isNeedShowDialog) {
logD(TAG, "${System.currentTimeMillis()},execute doWork function,result : retry")
Result.retry()
} else {
logD(TAG, "${System.currentTimeMillis()},execute doWork function,result : success")
Result.success()
}
}
}
自定义任务类,重写dowork
方法,从 doWork()
返回的 Result
会通知 WorkManager 任务:
- 已成功完成:
Result.success()
- 已失败:
Result.failure()
- 需要稍后重试:
Result.retry()
3.配置WorkRequest,包装运行任务的方式和时间
任务可以是一次性的,也可以是周期性的。对于一次性 WorkRequest
,请使用 OneTimeWorkRequest
,对于周期性工作,请使用 PeriodicWorkRequest
。WorkRequest
可以包含任务在运行时应遵循的约束、工作输入、延迟,以及重试工作的退避时间策略
val showDialogWorkRequest = OneTimeWorkRequest.Builder(DialogAppraiseTipsWorker::class.java)
.build()
4.将任务提交给系统
WorkManager.getInstance(this).enqueue(DialogAppraiseTipsWorker.showDialogWorkRequest)
WorkRequest
上面步骤中讲了可以通过WorkRequest来配置任务的运行方式和时间等信息。
任务添加约束
// Create a Constraints object that defines when the task should run
val constraints = Constraints.Builder()
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
.build()
// ...then create a OneTimeWorkRequest that uses those constraints
val showDialogWorkRequest = OneTimeWorkRequest.Builder(DialogAppraiseTipsWorker::class.java)
.setConstraints(constraints)
.build()
任务将仅在满足所有约束时才会运行,如果加了多个约束必须全部满足。
初始延迟
val showDialogWorkRequest = OneTimeWorkRequest.Builder(DialogAppraiseTipsWorker::class.java)
.setInitialDelay(10, TimeUnit.MINUTES)
.build()
设置任务10分钟后执行,默认立即执行
添加标记
添加一个Tag标记,用于后期来通过Tag取消任务和获取任务状态
val showDialogWorkRequest = OneTimeWorkRequest.Builder(DialogAppraiseTipsWorker::class.java)
.addTag(TAG)
.setInitialDelay(1, TimeUnit.MINUTES)
.build()
重试退避策略
val showDialogWorkRequest = OneTimeWorkRequest.Builder(DialogAppraiseTipsWorker::class.java)
.addTag(TAG)
.setInitialDelay(1, TimeUnit.MINUTES)
.setBackoffCriteria(BackoffPolicy.LINEAR, 5, TimeUnit.SECONDS)
.build()
设定重试任务前的等待时间,最小10秒,最大5小时。BackoffPolicy有两个值LINEAR(每次重试的时间线性增加,比如第一次10分钟,第二次就是20分钟)、EXPONENTIAL(每次重试时间指数增加)。
任务输入输出
Worker父类会有getInputData
和setOutputData
方法来输入和输出Data
,Data
里有个Map<String, Object> mValues
变量用来存放键值对信息。而Worker的getInputData
获取的Data是从WorkRequest
中的setInputData
方法得来的。
所以setInputData
是给Worker传输入参数的
Data imageData = new Data.Builder()
.putString(Constants.KEY_IMAGE_URI, imageUriString)
.build();
OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(UploadWorker.class)
.setInputData(imageData)
.build();
在Worker中输出Data类型返回值,添加到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);
}
}
观察工作状态
观察WorkInfo状态信息,满足条件后向用户显示信息。
WorkManager.getInstance(this).getWorkInfoByIdLiveData(DialogAppraiseTipsWorker.showDialogWorkRequest.id).observe(this, Observer { workInfo ->
logD(TAG, "observe: workInfo.state = ${workInfo.state}")
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
WorkManager.getInstance(this).cancelAllWork()
} else if (workInfo.state == WorkInfo.State.RUNNING) {
if (isActive) {
DialogAppraiseTipsWorker.showDialog(this)
WorkManager.getInstance(this).cancelAllWork()
}
}
})
这里我是通过WorkManager.getWorkInfoByIdLiveData(UUID)
来获取了LiveData<WorkInfo>
,还支持WorkManager.getWorkInfosByTagLiveData(String)
)通过Tag来检索,或者WorkManager.getWorkInfosForUniqueWorkLiveData(String)
) 通过唯一任务名称来检索都可以。