2018年谷歌I/O 发布了一系列辅助android开发者的实用工具,合称Jetpack,以帮助开发者构建出色的 Android 应用。
Jetpack 是一套库、工具和指南,可帮助开发者更轻松地编写优质应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您将精力集中放在所需的代码上。
使用WorkManager的好处
- 轻松地调度即使是应用退出甚至设备重启时仍然应该运行的可延迟异步任务
- 用统一的方法解决绝大部分后台滥用问题(滥用后台的任务导致设备变慢,电池损耗,数据流量丢失…问题)
使用WorkManager的流程
- 定义一个工作者 即 自定义一个
MyWorker
类继承Worker
(或者使用协程的话,得继承自CoroutineWorker),并实现doWork()
方法 - 创建一个工作(一次性,周期性等)| 指定工作者 | 设定条件(比如开机时,充电时…) | 传入数据inputData
- 将第二步创建的工作入队列
- 队列中的工作条件满足时,执行工作 即 第一步中的
doWork()
- 完成工作(并带回数据
outputData
)
WorkManager的对象我们不需要创建,只需要获取(singleton)
配置WorkRequest
在第2步创建工作时,可以有两种形式:一次性的及周期性的
- OneTimeWorkRequest
- PeriodicWorkRequest
OneTimeWorkRequest
用于创建一次性的任务,执行完毕自动结束
val workRequest: OneTimeWorkRequest = OneTimeWorkRequestBuilder<MyWorker>().build()
PeriodicWorkRequest
用于创建周期性执行的任务,使用方式与OneTimeWorkRequest基本一致
val workRequest= PeriodicWorkRequestBuilder<MyWorker>(20,TimeUnit.MINUTES).build()
添加到WorkContinuation中
在添加已经创建好的任务进队列时,有以下2种方式:
- 对于单个的WorkRequest,可以直接通过WorkManager的enqueue方法
workManager.enqueue(workRequest)
- 对于多个任务要加入工作队列中时,可以链式添加,这里有beginWith和beginUniqueWork两种方式
beginUniqueWork
与beginWith
不同的是它可以创建一个独一无二的链式请求
workManager.beginWith(workRequestA)
.then(workRequestB)
.enqueue()
val workContinuation=workManager.beginUniqueWork("A",ExistingWorkPolicy.REPLACE,workRequestA)
workContinuation.then(workRequestB).enqueue()
在创建独一无二的链式请求时,有三个参数:链式请求的名字,设置name相同时的表现,任务
第二个参数有以下几种选择:
- REPLACE: 当有相同name且未完成的链式请求时,将原来的进度取消并删除,重新加入新的链式请求
- KEEP: 当有相同name且未完成的链式请求时,链式请求保持不变
- APPEND: 当有相同name且未完成的链式请求时,将新的链式请求追加到原来的子队列中,即当原来的链式请求全部执行后才开始执行。
不管是哪种方式,原理都是创建出一个workContinuation对象,通过该对象,我们可以将其他任务继续添加进去
上面的链式添加都是串行执行任务,另外还可以并行执行任务
val workContinuation1=workManager.beginWith(workRequestA)
val workContinuation2=workManager.beginWith(workRequestB)
WorkContinuation.combine(arrayListOf(workContinuation1 , workContinuation2))
.enqueue()
任务一旦发起,是保证会一定执行的,只不过受到约束条件的限制,不能保证什么时间满足约束条件执行。
任务还可以被取消,有以下4种方式:
//通过request.id取消任务
WorkManager.getInstance(context).cancelWorkById(workRequest.id)
//通过request的tag取消任务
WorkManager.getInstance(context).cancelAllWorkByTag("tag")
//通过request的uniqueName取消任务
WorkManager.getInstance(context).cancelUniqueWork("Name")
//取消所有的work任务
WorkManager.getInstance(context).cancelAllWork()
原理
不管是OneTimeWorkRequest还是PeriodicWorkRequest他们都继承自WorkRequest,在WorkRequest类其中有一个内部成员变量mWorkSpec
,使用的是Room数据库,可以持久化存储,除非被clear data,所以能保证系统即使被重启,也可以确保任务得到执行
WorkSpec是一个持久化存储的类,会被存储在数据库中。它里面存储了一个WorkRequest的几乎所有信息,包括唯一标识id
,workerClassName
,input
,output
,constraints
等。
WorkManager是一个抽象类,它的实现类是WorkManagerImpl
,采用单例模式返回WorkManagerImpl
对象。WorkManagerImpl的主要任务是部分db数据读操作和线程调度,真正的任务操作都封装在具体的Runnable中,比如说StartWorkRunnable,StopWorkRunnable,EnqueueRunnable等,这些Runnable全部都在同一个后台线程执行。
任务调度之前,会先写入db持久化,并且判断是否有父任务没有执行,满足执行条件,会再次从db读取所有满足条件的WorkSpec。
最终会生成一个WorkerWrapper(实现了Runnable接口),在backThread实例化我们自定义的任务,调用doWork执行业务代码。