0x00 简述

WorkManager 是 Android Jetpack中的一部分,它主要是封装了 Android 后台任务的调度逻辑。在前文《Android后台任务处理指南》一文中知道,WorkManager 是高级 API,它实际是封装了JobScheduler, Firebase JobDispatcher, 和 AlarmManager 底层的使用,提供了简单且灵活易用的API,它有很多优势:

  • 支持异步一次性或周期任务

  • 支持网络、存储空间以及电量状态等约束

  • 可使用链式的调用方式来执行任务,也包括并行任务处理

  • 一个工作任务的执行结果可以作为下一个任务的输入

  • 兼容API 14 以上

  • 可以支持Google play services

  • 支持LiveData

0x01 理论篇——重要的类

WorkManager库中有一些非常重要的类,这些类帮助你构建后台执行的工作任务:

  • Worker:这是一个抽象类,它表示一个工作任务,继承这个类实现doWork()方法,这里就是实现执行任务的主要逻辑。

  • WorkRequest:表示一个工作任务请求,指定执行哪个Work,它还可以设置任务执行的约束条件。每一个WorkRequest都有一个自动生成的唯一ID。使用这个ID可以取消任务的执行,或者取得当前任务的执行状态。WorkRequest也是一个抽象类,使用的时候是框架库中提供的子类OneTimeWorkRequestPeriodicWorkRequest类,分别代表一次性任务和周期任务

    • WorkRequest.Builder:这是一个创建工作任务请求的辅助工具类。它有两个具体的实现:OneTimeWorkRequest.Builder类和PeriodicWorkRequest.Builder类,可以分别创建相应的任务请求实例。

    • Constraints:它表示工作任务执行的约束条件。指的是在哪一些系统条件下(例如只有网络连接情况下),这个工作任务会被执行。同样地,创建Constraints也有Builder方法:Constraints.Builder。约束类是可以在使用WorkRequest.Builder 创建的时候进行传递给WorkRequest

  • WorkManager:工作任务管理器,它是用于管理工作任务的请求队列的类。通过它可以把一个WorkRequest加入到任务队列中,然后根据系统的资源和约束条件对工作任务进行调度。

  • WorkStatus:工作状态类,它包含了工作任务当前的状态信息。WorkManager 为每一个WorkRequest都提供了LiveData对象,而LiveData对象又持有WorkStatus信息,因此通过LiveData可以监听到当前任务的状态信息,并且获取到任务结束后的执行结果。

通过上面的描述,可以简单的画出下面的关系图:

0x02 实践篇——工作流

假设我们在开发一个图片相关的APP,这个应用需要期地压缩它存储的图片。我们使用WorkManager来实现这个需求。这种情况,我们不关心压缩任务什么时候开始,只要开启一个压缩任务,其他的就交给WorkManager了。

  1. 定义Worker

我们首先要定义一个Worker类,并重写doWork()方法,这里定义了如何执行任务的具体逻辑。例如在此例子中,myCompress()就是具体的执行任务的逻辑。

class CompressWorker(context : Context, params : WorkerParameters)
: Worker(context, params) { override fun doWork(): Result {
// Do the work here--in this case, compress the stored images.
// In this example no parameters are passed; the task is
// assumed to be "compress the whole library."
myCompress() // Indicate success or failure with your return value:
return Result.SUCCESS // (Returning RETRY tells WorkManager to try this task again
// later; FAILURE says not to try again.)
}
}
 

doWork() 执行后还可以返回执行的结果:Result.SUCCESSResult.FAILUREResult.RETRY 分别表示成功失败重试

  1. 创建WorkRequest

使用WorkRequest的子类,根据具体业务创建对应的请求实例。例如本例中,使用一次性任务来构建请求。然后把任务请求加入到WorkManager管理的队列中。


val compressionWork = OneTimeWorkRequest.Builder<CompressWorker>().build()
WorkManager.getInstance().enqueue(compressionWork)
 

这样这个任务就交给WorkManager了,任务管理者根据当前系统情况(是否充电、网络状态等等)对任务进行调度。如果没有给WorkRequest指定约束条件,那么这个任务会马上执行。如果需要得到这个任务的状态,可以通过LiveData<WorkStatus>来监听。

WorkManager.getInstance().getStatusById(compressionWork.id)
.observe(lifecycleOwner, Observer { workStatus ->
// Do something with the status
if (workStatus != null && workStatus.state.isFinished) {
// ...
}
})

 

  1. 任务约束

可以给一个任务指定约束条件。例如,可以在设备空闲的时候、或者充电的时候执行任务。这种情况,可以使用Constraints.Builder来创建一个约束条件实例,然后传递到WorkRequest中。


// Create a Constraints object that defines when the task should run
val myConstraints = Constraints.Builder()
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
// Many other constraints are available, see the
// Constraints.Builder reference
.build() // ...then create a OneTimeWorkRequest that uses those constraints
val compressionWork = OneTimeWorkRequestBuilder<CompressWorker>()
.setConstraints(myConstraints)
.build()

 

最后,还是调用WorkManagerenqueue方法将WorkRequest加入队列。这时候,WorkManager在执行任务的时候就会考虑约束条件的情况。

  1. 取消任务

取消任务需要一个任务ID,可以通过WorkRequest来获取。然后调用WorkManagercancelWorkById方法来取消任务的执行。


val compressionWorkId:UUID = compressionWork.getId()
WorkManager.getInstance().cancelWorkById(compressionWorkId)
  1. 给任务设置Tag

可以给一组任务设置一个Tag。在创建 WorkRequest 的时候,可以执行给它指定一个Tag;而另一个任务请求也可以设置相同的Tag。

val cacheCleanupTask =
OneTimeWorkRequest.Builder<MyCacheCleanupWorker>()
.addTag("one-tag")
.build()
val loadImageTask = OneTimeWorkRequest.Builder<MyImageLoadWorker>()
.addTag("one-tag")
.build()
 

WorkManager提供了很多有用的API操作这些相同Tag的任务。例如,WorkManager.cancelAllWorkByTag() 可以取消具有相同Tag的一组任务;还可以通过WorkManager.getStatusesByTag()获取一组任务的状态列表。

  1. 周期任务

有些业务场景是需要重复执行一个任务的。例如,在一个图片应用中,可能会有一个定期检查需要压缩图片的任务。这时候可使用到 PeriodicWorkRequest.Builder 来创建一个周期任务。跟一次性任务一样,通过WorkManager.enqueue() 方法加入到工作任务队列中。


val photoCheckBuilder =
PeriodicWorkRequest.Builder<PhotoCheckWorker>(12, TimeUnit.HOURS)
// ...if you want, you can apply constraints to the builder here... // Create the actual work object:
val photoCheckWork = photoCheckBuilder.build()
// Then enqueue the recurring task:
WorkManager.getInstance().enqueue(photoCheckWork)

 

接下来的事情就交给 WorkManager 了。

0x03 引用

https://developer.android.com/topic/libraries/architecture/workmanager/basics

如何使用WorkManager执行后台任务(上)的更多相关文章

  1. 如何使用WorkManager执行后台任务(下)

    0x00 WorkManager的高级用法 在上一文中已经了解到 WorkManager的基本用法之后,今天来看看它的一些高级用法: 链式任务调用 唯一任务序列 传递参数和获取返回值 0x01 链式任 ...

  2. 执行后台任务的利器——Hangfire

    今年1月31日,在微软的MVP 2015社区大讲堂上,我给大家分享了一个演讲:在ASP.NET应用中执行后台任务.其中介绍了三种技术的应用:QueueBackgroundWorkItem.Hangfi ...

  3. MVP 2015社区大讲堂之:在ASP.NET应用中执行后台任务

    昨天下午,在微软的MVP 2015社区大讲堂上给大家分享了一个题目:在ASP.NET应用中执行后台任务.这是一点都不高大上,并且还有点土气的技术分享.不过我相信很多人都遇到过这样的问题. 虽然是一个很 ...

  4. 在ASP.NET应用中执行后台任务

    在ASP.NET应用中执行后台任务 昨天下午,在微软的MVP 2015社区大讲堂上给大家分享了一个题目:在ASP.NET应用中执行后台任务.这是一点都不高大上,并且还有点土气的技术分享.不过我相信很多 ...

  5. AsyncTask onPreExecute方法用于在执行后台任务前做一些UI操作

    1.实例化 TableListsTask task = new TableListsTask(ServerIP,"ALL", MenuActivity.this);   //第三参 ...

  6. echo json数据给ajax后, 需要加上exit,防止往下执行,带上其他数据,到时ajax失败

    01返回json数据给ajax后需要加上exit.返回json数据前不能有其他输出 function apply(){ if(IS_POST){$info['status'] = 1; echo js ...

  7. mysql数据库,如何在登录mysql之后执行操作系统上的SQL脚本?

    需求描述: 通过mysql客户端登录到mysql数据库,如何执行操作系统上的SQL脚本文件呢? 操作过程: 1.编写测试脚本文件 [mysql@redhat6 scripts]$ cat SeCoun ...

  8. 工作流JBPM_day02:3-预定义的活动1_4-预定义的活动2+在图片上高亮显示正在执行的上活动

    工作流JBPM_day02:3-预定义的活动1 工作流JBPM_day02:4-预定义的活动2+在图片上高亮显示正在执行的上活动 活动 Activity 预先定义好的活动 Start开始活动 End结 ...

  9. 让Jenkins执行GitHub上的pipeline脚本

    本文是<Jenkins流水线(pipeline)实战>系列的第二篇,上一篇搭建好了Jenkins环境并执行了一个简单的pipeline任务,当时我们直接在Jenkins网页上编写pipel ...

随机推荐

  1. Yarn工作机制

    概述 (0)Mr 程序提交到客户端所在的节点. (1)Yarnrunner 向 Resourcemanager 申请一个 Application. (2)rm将该应用程序的资源路径和Applicati ...

  2. c语言进阶3-有参函数

    一.       有参函数的定义 有参函数的定义格式如下: 类型标识符  函数名(形式参数表列) { 语句: } 如 void fun(int a,int b) { printf(“a+b=%d”,a ...

  3. C#2.0新增功能07 getter/setter 单独可访问性

    连载目录    [已更新最新开发文章,点击查看详细] 属性是一种成员,它提供灵活的机制来读取.写入或计算私有字段的值. 属性可用作公共数据成员,但它们实际上是称为访问器的特殊方法. 这使得可以轻松访问 ...

  4. TestNG中group的用法

    TestNG中的组可以从多个类中筛选组属性相同的方法执行. 比如有两个类A和B,A中有1个方法a属于组1,B中有1个方法b也属于组1,那么我们可以通过配置TestNG文件实现把这两个类中都属于1组的方 ...

  5. Nginx搭建详细

    Linux 安装Nginx搭建详细内容 进入:/usr/java/nginx位置下载nginx: wget et http://nginx.org/download/nginx-1.8.0.tar.g ...

  6. vue3.0中的双向数据绑定方法

    熟悉vue的人都知道在vue2.x之前都是使用object.defineProperty来实现双向数据绑定的 而在vue3.0中这个方法被取代了 1. 为什么要替换Object.definePrope ...

  7. iOS程序员 如何提升核心竞争力,防止自己被裁员?

    前言: 核心竞争力最早由普拉哈拉德和加里·哈默尔两位教授提出,通常认为核心竞争力,即企业或个人相较于竞争对手而言所具备的竞争优势与核心能力差异, 说白了就是你的优势,而且最好是独一无二的的优势,这就是 ...

  8. Kafka服务不可用(宕机)问题踩坑记

    背景 某线上日志收集服务报警,打开域名报502错误码. 收集服务由2台netty HA服务器组成,netty服务器将客户端投递来的protobuf日志解析并发送到kafka,打开其中一个应用的日志,发 ...

  9. QRCode生成二维码,jq QRCode生成二维码,QRCode生成电子名片

    [QRCode官网]http://phpqrcode.sourceforge.net/ PHP QRCode生成二维码 官网下载QRCode源码包,引入源码包中的 qrlib.php . <?p ...

  10. C#实现Hash应用全解

    1.引言 HASH是根据文件内容的数据通过逻辑运算得到的数值, 不同的文件(即使是相同的文件名)得到的HASH值是不同的. 通过一定的哈希算法(典型的有MD5,SHA-1等),将一段较长的数据映射为较 ...