Work
在运行期间有几种状态。在运行过程中, State
也随之改变。当任务开始是,状态是 ENQUEUED
。运行时转变为RUNNING
,运行结束时会变成 SUCCEEDED
、FAILED
。如果是重试的话,状态会重新回到ENQUEUED
。如果取消工作,状态就会变成 CANCELLED
。
SUCCEEDED
、FAILED
和 CANCELLED
均表示此工作的终止状态。如果您的工作处于上述任何状态,WorkInfo.State.isFinished()
都将返回 true。
以下是任务执行的流程图
上面是一个一次性任务的执行流程。如果是定时任务,那么就不会有SUCCEEDED
、FAILED
状态。以下是定时任务的流程图。
一般来说启动工作可以使用以下方式
WorkManager
.getInstance(this)
.enqueue(uploadWorkRequest)
不过如果我们无意中写了两次该代码,那么任务就会执行两次(虽说这个是不应该出现的)。为了避免这个问题,官方对一次性任务和定时任务分别提供了保证其唯一执行的方式。
这两种方法都接受 3 个参数:
String
。enum
可告知 WorkManager:如果已有使用该名称且尚未完成的唯一工作链,应执行什么操作。如需了解详情,请参阅冲突解决政策。WorkRequest
。参考代码如下:
val sendLogsWorkRequest =
PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
.setConstraints(Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"sendLogs",
ExistingPeriodicWorkPolicy.KEEP,
sendLogsWorkRequest
)
以下参考官网
调度唯一工作时,您必须告知 WorkManager 在发生冲突时要执行的操作。您可以通过在将工作加入队列时传递一个枚举来实现此目的。
对于一次性工作,您需要提供一个
ExistingWorkPolicy
,它支持用于处理冲突的 4 个选项。
REPLACE
:用新工作替换现有工作。此选项将取消现有工作。KEEP
:保留现有工作,并忽略新工作。APPEND
:将新工作附加到现有工作的末尾。此政策将导致您的新工作链接到现有工作,在现有工作完成后运行。现有工作将成为新工作的先决条件。如果现有工作变为
CANCELLED
或FAILED
状态,新工作也会变为CANCELLED
或FAILED
。如果您希望无论现有工作的状态如何都运行新工作,请改用APPEND_OR_REPLACE
。
APPEND_OR_REPLACE
函数类似于APPEND
,不过它并不依赖于先决条件工作状态。即使现有工作变为CANCELLED
或FAILED
状态,新工作仍会运行。对于定期工作,您需要提供一个
ExistingPeriodicWorkPolicy
,它支持REPLACE
和KEEP
这两个选项。这些选项的功能与其对应的 ExistingWorkPolicy 功能相同。
当工作启动后,可以通过以下方式获取相应的工作信息。
// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
上面三种获取的方式对应的赋值方式如下:
// by id
val uploadWorkRequest: OneTimeWorkRequest = OneTimeWorkRequest.from(WorkTest::class.java)//简单方式
val workerId = uploadWorkRequest.id
//by name
WorkManager
.getInstance(this)
.enqueueUniqueWork("workName",
ExistingWorkPolicy.KEEP,
uploadWorkRequest)
//by tag
val uploadWorkRequest: WorkRequest = //复杂的构建器方式
OneTimeWorkRequestBuilder<WorkTest>()
.addTag("first")
.build()
该查询会返回
WorkInfo
对象的ListenableFuture
,该值包含工作的id
、其标记、其当前的State
以及通过Result.success(outputData)
设置的任何输出数据。利用每个方法的
LiveData
变种,您可以通过注册监听器来观察WorkInfo
的变化(需要注意的是调用的函数名字是getWorkInfoByIdLiveData而不是getWorkInfoById())。例如,如果您想要在某项工作成功完成后向用户显示消息,您可以进行如下设置:workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(viewLifecycleOwner) { workInfo -> if(workInfo?.state == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show() } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
WorkManager 2.4.0 及更高版本支持使用
WorkQuery
对象对已加入队列的作业进行复杂查询。WorkQuery 支持按工作的标记、状态和唯一工作名称的组合进行查询。以下示例说明了如何查找带有“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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
WorkQuery
中的每个组件(标记、状态或名称)与其他组件都是AND
逻辑关系。组件中的每个值都是OR
逻辑关系。例如:(name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
。
WorkQuery
也适用于等效的 LiveData 方法getWorkInfosLiveData()
。
任务有时候需要取消,可以使用以下方式
// by id
workManager.cancelWorkById(syncWorker.id)
// by name
workManager.cancelUniqueWork("sync")
// by tag
workManager.cancelAllWorkByTag("syncTag")
WorkManager 会在后台检查工作的
State
。如果工作已经完成,系统不会执行任何操作。否则,工作的状态会更改为CANCELLED
,之后就不会运行这个工作。任何依赖于此工作的WorkRequest
作业也将变为CANCELLED
。目前,
RUNNING
可收到对ListenableWorker.onStopped()
的调用。如需执行任何清理操作,请替换此方法。如需了解详情,请参阅停止正在运行的工作器。
所以任务停止后,可以在重写的onStopped()
函数中处理收尾工作。也可以通过 ListenableWorker.isStopped()
来见擦汗任务是否停止,示例如下:
class WorkTest(val appContext: Context, workerParams: WorkerParameters): Worker(appContext, workerParams) {
override fun doWork(): Result {
if(isStopped){
return Result.success()
}
return Result.success()
}
}