• WorkManager的学习二


    一、前言

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

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

    以下是任务执行的流程图

    在这里插入图片描述

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

    在这里插入图片描述

    二、唯一工作

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

          WorkManager
                .getInstance(this)
                .enqueue(uploadWorkRequest)
    
    • 1
    • 2
    • 3

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

    这两种方法都接受 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
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    三、冲突策略

    以下参考官网

    调度唯一工作时,您必须告知 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>>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上面三种获取的方式对应的赋值方式如下:

    // 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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    该查询会返回 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”标记、处于 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)
    
    • 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")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    七、参考链接

    1. 管理工作  |  Android 开发者  |  Android Developers
  • 相关阅读:
    win 命令替代鼠标的操作
    多方通信许可证有何难
    常见JVM面试题及答案整理
    LTE网络优化笔记
    父子进程exec,fork等
    Linux的各种环境配置
    【Swift 60秒】12 - Arrays vs Sets vs Tuples
    【虚拟机栈】
    数组reduce方法详解
    网络安全阶段一学习笔记
  • 原文地址:https://blog.csdn.net/Mr_Tony/article/details/125605692