WorkManager 可以更容易的执行可延迟的异步任务,可以创建一个任务交给 WorkManager 立即执行或者在合适的时间执行。WorkManager 会自己选择一个合适的方式运行任务,当 App 在前台运行时,WorkManager 会在一个新的线程中运作该任务;如果 App 没有运行,可以不用谢任何逻辑代码,WorkManager 就可以根据项目的依赖以及设备 API 级别选择一个合适的方式运行任务,WorkManager 可以用 JobScheduler, Firebase JobDispatcher 或者 AlarmManager

WorkManager 还有一个惊人的功能,在退出程序后依然能够运行之前添加的任务

利用 WorkManager 可以很容易的把一个在指定条件下才执行的任务交给系统运行,WorkManager 需要 compileSdk 版本至少为 28 才能使用:

1
2
3
4
5
6
7
8
9
10
11
dependencies {
def work_version = "1.0.0-alpha07"

implementation "android.arch.work:work-runtime:$work_version" // use -ktx for Kotlin

// optional - Firebase JobDispatcher support
implementation "android.arch.work:work-firebase:$work_version"

// optional - Test helpers
androidTestImplementation "android.arch.work:work-testing:$work_version"
}

下面是 WorkManage 中几个比较重要的类:

  • Worker:用来执行任务的类,这是一个抽象类,需要继承该类
  • WorkRequest:定义一个任务,可以指定用哪个 Worker 来执行该任务,也可以添加执行该任务的条件。每一个 WorkRequest 都会生成一个唯一 ID;可以使用这个 ID 取消任务或者获取任务当前状态,这也是一个抽象类,它有两个子类可以使用, OneTimeWorkRequestPeriodicWorkRequest,从命名上就能区分出来两个类的区别,一个执行单次任务,一个执行循环任务
    • WorkRequest.Builder:如果不想用定义好的子类,同样也可以利用它来创建一个 WorkRequest
    • Constraints:用来指定任务运行的条件,通过 Constraints.Builder 来创建,在创建 WorkRequest 之前把 Constraints 传递给 WorkRequest.Builder 即可
  • WorkManager:存放和以及管理任务
  • WorkStatus:包含任务的一些信息,WorkManager 会为每一个 WorkRequest 提供一个 LiveData,该 LiveData 持有一个 WorkStatus 对象,观察该 LiveData 就能获取任务当前状态以及返回值

基本用法

执行任务

项目中需要定时检测本地日志文件的大小,如果过大就删除。之前的解决方案用的是 RxJava 的 interval 操作符,现在换成使用 WorkManager 看看有什么区别,首先定义一个继承了 Worker 的类:

1
2
3
4
5
6
7
8
9
10
class CheckFileSizeWorker : Worker() {
override fun doWork(): Result {
checkFileSize()
return Result.SUCCESS
}

private fun checkFileSize() {
println("checkFileSize")
}
}

doWork 函数的返回值中一共有三个状态 Result.SUCCESSResult.FAILUERResult.RETRY

1
2
val checkFillSizeWorker = OneTimeWorkRequest.Builder(CheckFillSizeWorker::class.java).build()
WorkManager.getInstance().enqueue(checkFillSizeWorker)

获取状态

使用 OneTimeWorkRequest 创建一个任务,如果不指定一个执行条件,这个任务会立即执行,可以通过这个任务的 ID 来获取该任务的状态:

1
2
3
4
WorkManager.getInstance().getStatusById(checkFillSizeWorker.id)
.observe(this, Observer {
println(it)
})

如果使用 PeriodicWorkRequest 来执行循环任务,有几个问题需要注意。它默认循环的最小间隔是15分钟,其中还有一个 叫做 flexInterval 的参数,最小间隔是5分钟,且不能超过循环间隔时间。这个参数是用来指定一个弹性时间,举个栗子说明一下,如果使用默认的参数,那么这个循环任务其实不是刚好过15分钟就执行,而是通过循环间隔时间减去这个弹性时间,也就是10分钟后才是任务开始执行的时间,WorkManager 会在前一个任务结束的10分钟到15分钟之间执行下一个任务

设置执行条件

接下来给这个任务指定一个执行条件,这个时候就需要用到 Constraints 这个类了:

1
2
3
4
5
6
// 还有电量是否低,是否正在充电,设备是否空闲等条件
val constraints = Constraints.Builder()
.setRequiresDeviceIdle(true)
.build()

val checkFillSizeWorker = OneTimeWorkRequest.Builder(CheckFillSizeWorker::class.java).setConstraints(constraints).build()

取消任务

通过任务的 ID 来取消该任务:

1
WorkManager.getInstance().cancelWorkById(checkFillSizeWorker.id)

如果想要取消一组任务,需要给这些任务指定了一个 tag,通过 cancelAllWorkByTag 函数来取消