Jetpack—WorkManager使用
Jetpack—WorkManager使用
WorkManager简介
WorkManager是Jetpack提供的异步任务管理组件。使用WorkManager,您可以轻松调度那些即使在退出应用或重启设备时仍应运行的可延期异步任务。
WorkManager会根据当前设备API适时的调度不同的组件实现异步任务。(包括 FirebaseJobDispatcher、GcmNetworkManager 和 JobScheduler)
相关类
- Worker:(抽象父类:ListenableWorker)要执行的任务,需重写doWork()方法。
- WorkRequest:
1、定义Worker运行方式和时间。
2、在最简单的情况下,您可以使用 OneTimeWorkRequest。或者循环任务PeriodicWorkRequest。
3、通过WorkRequest.Builde构建实例,另返回唯一标识。 - Constraints:任务约束,设置工作执行的条件,如电量、网络状态、电池状态…
- WorkManager:工作管理类,对工作进行设置和调度。
- Observer:观察任务结果和进度。
WorkManager 2.3.0-alpha01 为设置和观察工作器的中间进度添加了一流支持,可以观察任务进度。
基本用法
1、依赖
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 UploadWorker(appContext: Context, workerParams: WorkerParameters):
Worker(appContext, workerParams) {
override fun doWork(): Result {
// Do the work here--in this case, upload the images.
Log.e("UploadWorker", "执行了 doWork() 操作!")
// Indicate whether the work finished successfully with the Result
return Result.success()
}
}
创建WorkRequest
//一次性工作
val uploadWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<UploadWorker>()
.build()
//周期性工作
val saveRequest =
PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
// Additional configuration
.build()
将任务提交到WorkManager
WorkManager
.getInstance(myContext)
.enqueue(uploadWorkRequest)
任务约束:
使用Constraints.Builder()创建并配置Constraints对象
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
val myWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWork>()
.setConstraints(constraints)
.build()
任务延迟:
如果工作没有约束,或者当工作加入队列时所有约束都得以满足,那么系统可能会选择立即运行该工作。如果您不希望工作立即运行,可以将工作指定为在经过一段最短初始延迟时间后再启动。
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.setInitialDelay(10, TimeUnit.MINUTES)
.build()
高级用法
链式任务
- WorkManager允许您创建和排队指定多个任务的工作序列,以及它们应运行的顺序
- 使用该WorkManager.beginWith() 方法创建一个序列 ,并传递第一个OneTimeWorkRequest对象; 该方法返回一个WorkContinuation对象
- 使用 WorkContinuation.then()添加剩余的对象
- 最后调用WorkContinuation.enqueue()将整个序列排入队列
- 如果任何任务返回 Worker.Result.FAILURE,则整个序列结束
- 链式任务只能添加OneTimeWorkRequest对象
例子:
/**
* 代码中,plantName1, plantName2, plantName3并发执行,并把结果链接起来。
* 结果传递给cache,并执行cache任务。
* 最后执行upload任务,并接收cache结果。
*/
WorkManager.getInstance(myContext)
// Candidates to run in parallel
.beginWith(listOf(plantName1, plantName2, plantName3))
// Dependent work (only runs after all previous work in chain)
.then(cache)
.then(upload)
// Call enqueue to kick things off
.enqueue()
输入合并
当链接 OneTimeWorkRequest 实例时,父级工作请求的输出将作为子级的输入传入。因此在上面的示例中,plantName1、plantName2 和 plantName3 的输出将作为 cache 请求的输入传入。
val cache: OneTimeWorkRequest = OneTimeWorkRequestBuilder<PlantWorker>()
.setInputMerger(ArrayCreatingInputMerger::class)
.setConstraints(constraints)
.build()
WorkManager 提供两种不同类型的 InputMerger:
-
OverwritingInputMerger 会尝试将所有输入中的所有键添加到输出中。如果发生冲突,它会覆盖先前设置的键。
-
ArrayCreatingInputMerger 会尝试合并输入,并在必要时创建数组。
唯一工作
避免任务重复,可以指定任务唯一,并设置唯一策略。
/**
*这两种方法都接受 3 个参数:
*uniqueWorkName - 用于唯一标识工作请求的 String。
*existingWorkPolicy - 此 enum 可告知 WorkManager 如果已有使用该名称的唯一工作链,应执行什么操作。如需*了解详情,请参阅冲突解决政策。
*work - 要调度的 WorkRequest。
*/
WorkManager.enqueueUniqueWork()(用于一次性工作)
WorkManager.enqueueUniquePeriodicWork()(用于定期工作)
例子:
/**
*对于一次性工作,您需要提供一个 ExistingWorkPolicy,它支持用于处理冲突的 4 个选项。
*用新工作 REPLACE 现有工作。此选项将取消现有工作。
*KEEP 现有工作,并忽略新工作。
*将新工作 APPEND 到现有工作的末尾。此政策将导致您的新工作链接到现有工作,在现有工作完成后运行。
*APPEND_OR_REPLACE 功能类似于 APPEND,不过它并不依赖于先决条件工作状态。如果现有工作是 CANCELLED 或 FAILED,新工作仍会运行。
**/
val sendLogsWorkRequest =
PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
.setConstraints(Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"sendLogs",
ExistingPeriodicWorkPolicy.KEEP,
sendLogsWorkRequest
)
工作状态
-
只要工作成功完成(即,返回 Result.success()),OneTimeWorkRequest 链便会按顺序执行。运行时,工作请求可能会失败或被取消,这会对依存工作请求产生下游影响。
-
当第一个 OneTimeWorkRequest 被加入工作请求链队列时,所有后续工作请求会被屏蔽,直到第一个工作请求的工作完成为止。
-
在加入队列且满足所有工作约束后,第一个工作请求开始运行。如果工作在根 OneTimeWorkRequest 或 List 中成功完成(即返回 Result.success()),系统会将下一组依存工作请求加入队列。
-
如果在工作器处理工作请求时出现错误,您可以根据您定义的退避政策来重试该请求。重试请求链中的某个请求意味着,系统将使用提供给该请求的输入数据仅对该请求进行重试。并行运行的所有其他作业均不会受到影响(重试和退避政策将在下文介绍)。
-
如果该重试政策未定义或已用尽,或者您以其他方式已达到 OneTimeWorkRequest 返回 Result.failure() 的某种状态,该工作请求和所有依存工作请求都会被标记为 FAILED.
观察工作器的中间进度
先前条件
获取任务和任务集:
简单查询
// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
复杂查询
以下示例说明了如何查找带有“syncTag”标记、处于 FAILED 或 CANCELLED 状态,且唯一工作名称为“preProcess”或“sync”的所有工作。
val workQuery = WorkQuery.Builder
.fromTags(listOf("syncTag"))
.addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
.addUniqueWorkNames(listOf("preProcess", "sync")
)
.build()
val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)
观察任务
workManager.getWorkInfoByIdLiveData(syncWorker.id)
.observe(viewLifecycleOwner) { workInfo ->
if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
Snackbar.make(requireView(),
R.string.work_completed, Snackbar.LENGTH_SHORT)
.show()
}
}
更新进度:
对于使用 ListenableWorker 或 Worker 的 Java 开发者,setProgressAsync() API 会返回 ListenableFuture;更新进度是异步过程,因为更新过程包括将进度信息存储在数据库中。在 Kotlin 中,您可以使用 CoroutineWorker 对象的 setProgress() 扩展函数来更新进度信息。
import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.WorkerParameters
import kotlinx.coroutines.delay
class ProgressWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
companion object {
const val Progress = "Progress"
private const val delayDuration = 1L
}
override suspend fun doWork(): Result {
val firstUpdate = workDataOf(Progress to 0)
val lastUpdate = workDataOf(Progress to 100)
setProgress(firstUpdate)
delay(delayDuration)
setProgress(lastUpdate)
return Result.success()
}
}
观察进度
WorkManager.getInstance(applicationContext)
// requestId is the WorkRequest id
.getWorkInfoByIdLiveData(requestId)
.observe(observer, Observer { workInfo: WorkInfo? ->
if (workInfo != null) {
val progress = workInfo.progress
val value = progress.getInt(Progress, 0)
// Do something with progress information
}
})
重试和避退策略
如果您需要让 WorkManager 重试工作,可以从工作器返回 Result.retry()。然后,系统将根据退避延迟时间和退避政策重新调度工作。
退避延迟时间指定了首次尝试后重试工作前的最短等待时间。此值不能超过 10 秒(或 MIN_BACKOFF_MILLIS)。
退避政策定义了在后续重试过程中,退避延迟时间随时间以怎样的方式增长。WorkManager 支持 2 个退避政策,即 LINEAR 和 EXPONENTIAL。
每个工作请求都有退避政策和退避延迟时间。默认政策是 EXPONENTIAL,延迟时间为 10 秒,但您可以在工作请求配置中替换此设置。
以下是自定义退避延迟时间和政策的示例。
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.setBackoffCriteria(
BackoffPolicy.LINEAR,
OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS)
.build();
上一篇: 问题 J: Master of GCD
下一篇: tuple