5月8号, I/O大会上推出了Architeture新组件WorkManager。 由于Android版本的不断更新,后台任务的处理变得越来越复杂。 因此,Google发布了 WorkManager(作为JetPack的一部分)来帮助开发者解决这一难题。
1
WorkManager简介
使用场景总结::当应用完全退出后,需要管理要在后台工作的任务
On the last Google I/O Android framework, the team announced WorkManager:
WorkManager aims to simplify the developer experience by providing a first-class API for system-driven background processing. It is intended for background jobs that should run even if the app is no longer in the foreground. Where possible, it uses JobScheduler or Firebase JobDispatcher to do the work; if your app is in the foreground, it will even try to do the work directly in your process.
注意[翻译]:WorkManager适用于那些即使应用程序退出,系统也能够保证这个任务正常运行的场景,比如将应用程序数据上传到服务器。它不适用于应用进程内的后台工作,如果应用进程消失,就可以安全地终止,对于这种情况,推荐你使用线程池
2
WorkManager库的架构
从图中可以看出,WorkManager执行队列中包含JobScheduler,JobDispatcher,Executor,AlarmManager。
WorkManager在底层会根据你的设备情况进行有选择的调度。但这跟AsyncTask, ThreadPool, RxJava这调度管理工具不同的是,WorkManager能帮助你在应用中在后台线程干活,及时进程被杀死活或关闭。但上述这些工具在进程结束后及结束所有任务,其实Google自己也说了:”WorkManager并不是为了那种在应用内的后台线程而设计出来的. 这种需求你应该使用ThreadPool”。
3
WorkManager API的特点
1. 易于调度
2. 易于取消
WorkManager给每个任务分配了UUID,使用这个唯一的ID你就可以随时取消任务。
3.易于查询
4.支持Android所有版本
4
WorkManager使用方法
Work manager APIs建立在几个类上,你必须继承一些抽象类来安排任务。
Worker:在WorkManager世界中,Worker等同于需要在后台执行的任务或作业。这是一个抽象类。你需要继承它。您的Worker类包含有关如何执行该任务的信息,但它没有关于何时运行的信息。
WorkRequest:它代表了工作调度请求。每个工作必须在安排工作之前创建工作请求。 WorkRequest将包含工作的唯一标识,约束条件说明应在哪种情况下执行任务。这是一个抽象类。该库提供了这个类的两个直接子类:OneTimeWorkRequest和PeriodicWorkRequest。
WorkRequest.Builder:用于创建WorkRequest对象的辅助类,同样,我们要使用它的一个子类,OneTimeWorkRequest.Builder 和PeriodicWorkRequest.Builder 。
Constraints:指定任务在何时运行(例如,“仅在连接到网络时”)。我们可以通过Constraints.Builder 来创建Constraints对象,并在创建WorkRequest之前,将 Constraints 对象传递给 WorkRequest.Builder。
WorkManager:它是基于WorkRequest中定义的约束来管理和调度任务的类。
WorkStatus:这个类包装了任何work请求的状态,你可以通过唯一的id来查询任何work的状态。 基本工作流程如图所示:
gradle依赖:
https://developer.android.com/topic/libraries/architecture/adding-components
WorkManager类已经在 androidx.work 包中,但目前依赖于 Support Library 27.1 以及相关的 Arch组件版本,将来会发布带有 AndroidX 依赖项的WorkManager版本。
dependencies {
def work_version = "1.0.0-alpha01"
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"}
基本工作流程:
首先,我们需要定义自己的Worker类,然后重写此类的 doWork() 方法,我们需要指定Worker类如何执行这个操作,但是不应该出现任何关于任务在何时运行的信息。
class CompressWorker : Worker() {
override fun doWork(): WorkerResult { // 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 WorkerResult.SUCCESS // (Returning RETRY tells WorkManager to try this task again
// later; FAILURE says not to try again.)
}
}
接下来,我们要创建一个基于此Worker 的OneTimeWorkRequest对象,然后使用WorkManager让这个任务入队:
val compressionWork = OneTimeWorkRequestBuilder<CompressWorker>().build()
WorkManager.getInstance().enqueue(compressionWork)
WorkManager会选择适当的时间运行这个任务,平衡诸如系统负载,设备是否插入等考虑因素。在多数情况下,如果我们没有指定任何约束条件,WorkManager会立即运行我们的任务。如果我们需要检查任务的状态,我们可以通过获取合适的LiveData <WorkStatus>的句柄来获取WorkStatus对象。例如,如果我们想检查任务是否完成,可以使用如下代码:
WorkManager.getInstance().getStatusById(compressionWork.id)
.observe(lifecycleOwner, Observer { workStatus -> // Do something with the status
if (workStatus != null && workStatus.state.isFinished) { // ...
}
})
任务约束条件:
如果我们愿意,我们还可以限制任务运行的时间。例如,我们可能想要指定该任务只在设备闲置并接通电源时运行。在这种情况下,我们需要创建一个OneTimeWorkRequest.Builder对象,并使用这个构造器创建实际的OneTimeWorkRequest:
// Create a Constraints that defines when the task should runval myConstraints = Constraints.Builder()
.setRequiresDeviceIdle(true)
.setRequiresCharging(true) // Many other constraints are available, see the
// Constraints.Builder reference
.build()
val compressionWork = OneTimeWorkRequestBuilder<CompressWorker>()
.setConstraints(myConstraints)
.build()
然后像之前代码一样将新的OneTimeWorkRequest对象传递给WorkManager.enqueue(), WorkManager在查找运行任务的时间时会考虑我们的约束条件。
取消任务:
当我们将任务入列后,我们还可以取消这个任务。要取消任务,我们需要这个任务的Work ID,当然Work ID可以从WorkRequest对象中获取。例如,以下代码将取消上一节中的compressionWork请求:
UUID compressionWorkId = compressionWork.getId();
WorkManager.getInstance().cancelByWorkId(compressionWorkId);
WorkManager 会尽最大努力取消任务,但实质上这是不确定的 - 当我们尝试取消任务时,任务可能已经运行或完成。
WorkManager还提供方法来取消 唯一工作序列(在高级用法中会有所涉及)中的所有任务,或尽最大努力的取消具有指定标记的所有任务。
详细使用方法请参考:官网https://developer.android.com/topic/libraries/architecture/workmanager
googlecodelabs关于WorkManager应用的使用方法Demo https://github.com/googlecodelabs/android-workmanager
特别鸣谢: https://juejin.im/post/5b04d064f265da0b80711759 https://android.jlelse.eu/exploring-jetpack-scheduling-tasks-with-work-manager-fba20d7c69bf