WorkManager的学习二

一、前言

Work在运行期间有几种状态。在运行过程中, State也随之改变。当任务开始是,状态是 ENQUEUED。运行时转变为RUNNING,运行结束时会变成 SUCCEEDEDFAILED。如果是重试的话,状态会重新回到ENQUEUED。如果取消工作,状态就会变成 CANCELLED

SUCCEEDEDFAILEDCANCELLED 均表示此工作的终止状态。如果您的工作处于上述任何状态,WorkInfo.State.isFinished() 都将返回 true。

以下是任务执行的流程图

在这里插入图片描述

上面是一个一次性任务的执行流程。如果是定时任务,那么就不会有SUCCEEDEDFAILED状态。以下是定时任务的流程图。

在这里插入图片描述

二、唯一工作

一般来说启动工作可以使用以下方式

      WorkManager
            .getInstance(this)
            .enqueue(uploadWorkRequest)

不过如果我们无意中写了两次该代码,那么任务就会执行两次(虽说这个是不应该出现的)。为了避免这个问题,官方对一次性任务和定时任务分别提供了保证其唯一执行的方式。

这两种方法都接受 3 个参数:

  • uniqueWorkName - 用于唯一标识工作请求的 String
  • existingWorkPolicy - 此 enum 可告知 WorkManager:如果已有使用该名称且尚未完成的唯一工作链,应执行什么操作。如需了解详情,请参阅冲突解决政策
  • work - 要调度的 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:将新工作附加到现有工作的末尾。此政策将导致您的新工作链接到现有工作,在现有工作完成后运行。

现有工作将成为新工作的先决条件。如果现有工作变为 CANCELLEDFAILED 状态,新工作也会变为 CANCELLEDFAILED。如果您希望无论现有工作的状态如何都运行新工作,请改用 APPEND_OR_REPLACE

  • APPEND_OR_REPLACE 函数类似于 APPEND,不过它并不依赖于先决条件工作状态。即使现有工作变为 CANCELLEDFAILED 状态,新工作仍会运行。

对于定期工作,您需要提供一个 ExistingPeriodicWorkPolicy,它支持 REPLACEKEEP 这两个选项。这些选项的功能与其对应的 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()
   }
}

五、复杂的查询

WorkManager 2.4.0 及更高版本支持使用 WorkQuery 对象对已加入队列的作业进行复杂查询。WorkQuery 支持按工作的标记、状态和唯一工作名称的组合进行查询。

以下示例说明了如何查找带有“syncTag”标记、处于 FAILEDCANCELLED 状态,且唯一工作名称为“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)

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()
    }
}

七、参考链接

  1. 管理工作  |  Android 开发者  |  Android Developers
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值