注:原文地址
5月8号, I/O大会上又推出了两个新的Architeture Component库: Navigation与 WorkManager. 这里就先介绍一下 WorkManager。

WorkManager简介

其实就是”管理一些要在后台工作的任务, – 即使你的应用没启动也能保证任务能被执行”。

1. 为何不用JobScheduler, AlarmManger来做?

其实这个想法很对. WorkManager在底层也是看你是什么版本来选到底是JobScheduler, AlamarManager来做。
JobScheduler是Android 5.x才有的. 而AlarmManager一直存在. 所以WorkManager在底层, 会根据你的设备情况, 选用JobScheduler, Firebase的JobDispatcher, 或是AlarmManager。

2.为啥不用AsyncTask, ThreadPool, RxJava?

这一点就要特别说明一下了. 这三个和WorkManager并不是替代的关系. 这三个工具, 能帮助你在应用中开后台线程干活, 但是应用一被杀或被关闭, 这些工具就干不了活了。

而WorkManager不是, 它在应用被杀, 甚至设备重启后仍能保证你安排给他的任务能得到执行。

其实Google自己也说了:”WorkManager并不是为了那种在应用内的后台线程而设计出来的. 这种需求你应该使用ThreadPool”。

WorkManager实例

1. 导入WorkManager

在app/build.gradle文件中加入如下依赖配置:
Kotlin

implementation "android.arch.work:work-runtime-ktx:1.0.0-alpha01"

Java

implementation "android.arch.work:work-runtime:1.0.0-alpha01"

2.一个定期Pull的实例

以我在2012年做过的一个项目为例, 当时我在做一个电商项目. 我们有一个需求是要定时推给用户一些我们推荐的单品, 但是当时集团还没有push service组件呢, 所以我们当时为了及时上线, 选用的策略是”pull策略”. 客户端定时去后台拉取, 看有没有新的推荐.
这时我们要分两步走. 第一步是确定要干什么活(去后台pull推荐信息);第二步是让这个活入队列。

1,代码实现上也分为两步:Worker是干活的主体,它只管轮到了它时要做的工作,不管其它的东西。首先,新建个Worker的子类, 重写它的doWork()方法:

class PullWorker : Worker() {override fun doWork(): WorkerResult {// 模拟设置页面中的"是否接受推送"是否被勾选val isOkay = this.inputData.getBoolean("key_accept_bg_work", false)if(isOkay) {Thread.sleep(5000) //模拟长时间工作val pulledResult = startPull()val output = Data.Builder().putString("key_pulled_result", pulledResult).build()outputData = outputreturn WorkerResult.SUCCESS} else {return WorkerResult.FAILURE}}fun startPull() : String{return "szw [worker] pull messages from backend"}
}

2,把Worker包装成一个WorkRequest, 并入列。此时,WorkRequest就多了一些新属性。

  • ID(一般是一个UUID, 以保证唯一性),
  • 何时执行,
  • 有没有限制(如只有在充电并连网时才执行此任务),
  • 执行链 (当某任务执行完了, 才能轮到我执行)。

然后使用WorkManager将WorkRequest对象入列。

class PullEngine {fun schedulePull(){//java就请用PeriodicWorkRequest.Builder类val pullRequest = PeriodicWorkRequestBuilder<PullWorker>(24, TimeUnit.HOURS).setInputData(Data.Builder().putBoolean("key_accept_bg_work", true).build()).build()WorkManager.getInstance().enqueue(pullRequest)}
}

讲解

  • 1.干活的是 Worker 类。我们一般是新建个Worker的子类, 并重写doWork()方法。但是,doWork() 方法是没有参数的,我们有时有参数的需求,怎么办? 这时就要用上Worker.getInputData()方法了。
  • 2.同理, doWork()方法是返回void的。你要是有结果想传出去, 就可以用Worker.setOutputData()。
  • 3.上面的两个方法所得到/设置的数据类型都是Data. 这个Data很类似我们Android中的Bundle, 也有putInt(key, value), getString(key, defaultValue)这样的方法。一般Data的生成, 是用Data.Builder类. 如:
val output = Data.Builder().putInt(key, 23).build()
  • 4.上面讲了WorkRequest其实就是入列的一个实体, 它包装了Worker在内. 但我们一般不直接使用WorkReqeust类, 多是用它的子类: OneTimeWorkRequest, 或是PeriodWorkReqeust。因为我们的pull需求是每天都要去拉一次, 所以这里我们没有用OneTimeWorkRequest, 而是构建了一个24小时就重复干活的PeriodicWorkReqeust。

进阶

WorkManager 提供了一个接口让我们拿到结果, 这个东东就是 WorkStatus. 你可以由id得到你想要的那个任务的WorkStatus. 这个 WorkStatus 其实就是知道这任务没有完成, 有什么返回值.

因为前后台要解耦合的原因, 所以这个工作其实是由LiveData来完成的. 既然有LiveData, 那我们肯定要有一个 LifecycleOwner 了(一般是我们的 AppcompatActivity).

来看个例子. 以上面的pull例子为例, 若我们拉到了结果, 就显示一个 notification (这里为简便, 是收到结果后就打印一下日志)。

class PullEngine {fun schedulePull(){val pullRequest = PeriodicWorkRequestBuilder<PullWorker>(24, TimeUnit.HOURS).build()WorkManager.getInstance().enqueue(pullRequest)// 下面两行是新加的, 用来存任务的IDval pullRequestID = pullRequest.idMockedSp.pullId = pullRequestID.toString() // 模拟存在SharedPreference中}
}
class PullActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// UUID实现了Serializable接口. 也能由toString(), fromString()与String互转val uuid = UUID.fromString(MockedSp.pullId)WorkManager.getInstance().getStatusById(uuid).observe(this, Observer<WorkStatus> { status ->if (status != null){val pulledResult = status.outputData.getString("key_pulled_result", "")println("szw Activity getResultFromBackend : $pulledResult")}})}
}

其中,observe()方法是用来监听的. 它的参数分别是: observer(LifecycleOwner, Observer<WorkStatus>)

1,入参/返回值

入参: WorkRequest.Builder.setInputData()
Worker类: 可以getIntpuData(), 以及setOutputData()
返回值: 由LiveData监听, 可以得到WorkStatus. 而WorkStatus就有getOutputDat()方法
需要注意的是,这里说的inputData、outputDat, 都不是普通的int、string,而是Data类。

2,如果任务执行完了, 应用却没被启动怎么办? 会强行启动应用来显示UI变化吗?

好问题. 但严格来说, 这个其实不是WorkManager的问题, 而是LiveData的问题.
LiveData自己本身就是和Activity的生命周期绑定的. 你不用说应用被杀了, 就是你退出了这个注册的Activity, 你都收不到LiveData的通知. 所以说你的应用被杀, 任务又执行完了时, 是没有UI通知的, 更不会强行启动你的启动。

3,任务链

WorkManager.getInstance().beginWith(workA).then(workB).then(workC).enqueue()

这样就会按workA, workB, workC的顺序来执行. workA执行完了, 才会接着执行workB。WorkManager甚至还能执行:

A --> B--> E
C --> D

这样的形式,,即A执行完了才执行了B, C执行完才执行D. B,D都执行完了才执行E。

5,插入任务时, 已经有相同的任务时, 怎么办?

WorkManager可以用beginUniqueWork()来执行唯一工作队列(“unique work sequence”). 若有任务有重复时, 怎么办?
这个主要是一个ExistingWorkPolicy类。这个类也是WorkManager包中的类,它其实是一个Enum。其值有:

  • REPLACE: 用新任务来取代已经存在的任务
  • KEEP: 保留已经存在的任务. 忽视新任务
  • APPEND: 新任务入列. 新旧任务都存在于队列中.

总结

总体来说, WorkManager并不是要取代线程池/AsyncTask/RxJava. 反而是有点AlarmManager来做定时任务的意思. 即保证你给它的任务能完成, 即使你的应用都没有被打开, 或是设备重启后也能让你的任务被执行.
WorkManager在设计上设计得比较好. 没有把worker, 任务混为一谈, 而是把它们解耦成Worker, WorkRequest. 这样分层就清晰多了, 也好扩展. (如以后再有一个什么WorkRequest的子类出来)
最后, WorkManager的入参出参设计得不错. WorkReqeust负责放入参数, Worker处理并放置返回值, 最后WorkStaus中取出返回值, 并由LiveData来通知监听者.

Android新架构组件WorkManager相关推荐

  1. android新架构,Android新架构组件 LifeCycles 简介

    一.前言 为了使开发者能尽快在 Android 平台上开发出高质量的项目,Android 官方推出了 Android Jetpack 项目,旨在从基础,架构,行为以及界面 4 大方面体系化地为我们提供 ...

  2. android 使用4大组件的源码,Android Jetpack架构组件之 Paging(使用、源码篇)

    1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...

  3. android新架构模式_Android MVIReact架构模式

    android新架构模式 If you are already aware of basic principles of architecture patterns and MVVM and MVI ...

  4. Android 官方架构组件 Navigation 使用详解

    前言 前段时间,我在做项目开发的时候对Fragment的管理遇到几个小问题,总觉得在现阶段封装好的Fragment管理器不太优雅.这成为我下决心学习Jetpack在很早之前推出的Navigation库 ...

  5. Android官方架构组件Paging:分页库的设计美学

    本文已授权 微信公众号 玉刚说 (@任玉刚)独家发布. 2019/12/24 补充 距本文发布时隔一年,笔者认为,本文不应该作为入门教程的第一篇博客,相反,读者真正想要理解 Paging 的使用,应该 ...

  6. Android Jetpack架构组件之 Room(使用、源码篇)

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发 ...

  7. android置组件下面,Android Jetpack架构组件(十二)之Hilt

    一. 依赖注入简介 依赖注入(英文Dependency Injection,简写DI)是一种被广泛使用的编程技术,主要的作用代码解耦. 借助依赖注入,我们可以轻松的管理类之间的依赖,并最终建立高可维护 ...

  8. Android Jetpack架构组件(一)带你了解Android Jetpack

    本文首发于微信公众号「后厂村码农」 前言 Android已经发展了11年,可以说是比较成熟的技术了,一开始时框架很少,也没有什么规范,所有的代码都是要自己写,比如网络请求,数据库请求,数据解析等等.后 ...

  9. android官方架构room,Android 官方架构组件介绍之 Room(翻译)

    持久库Room Room在SQLite上提供了一个抽象层,以便在利用SQLite的全部功能的同时使流畅的数据库访问. 需要处理一些重要的结构化数据的App通常会从本地的持久数据中受益匪浅.最常见的就是 ...

最新文章

  1. 笑死!“盒马”把自己的ID给玩没了...
  2. 微信小程序 canvas 内容(宽高) 兼容不同机型
  3. python数据库self函数_Python常用功能函数系列总结(四)之数据库操作
  4. Navicat远程连接linux下mysql服务器1045错误解决办法在这儿
  5. 构建ASP.NET网站十大必备工具
  6. matlab gui 制动程序设计,Matlab的GUI程序设计程序.doc
  7. 电动汽车V2G及直流母线在新能源微电网中的应用
  8. Java常用英文单词
  9. 核磁共振测井设备市场现状及未来发展趋势分析
  10. android数据写入文件格式,Android 本地文件保存数据(2020-08-07)
  11. 多元线性回归-Lasso
  12. yogabook安卓版root方法
  13. k8s v1.22版本中Ingress配置:no matches for kind “Ingress“ in version “networking.k8s.io/v1beta1“
  14. python中如何解决类互相调用问题_python中同一个类,带参的方法直接如何相互调用...
  15. 隐藏在sketch的10个实用技巧,学会就是赚到!
  16. iText5/iText7添加书签对比
  17. 你会成为屋里最有趣的人
  18. 思科在中国已建成355所网络技术学院
  19. 关于android分享(sharedsdk的简单使用)
  20. ‎平面設計師需要瞭解的8個印刷知識‎

热门文章

  1. Successful Lisp - Cover
  2. EC20 AT调试笔记
  3. iPad怎么下载pdf 通过chrome
  4. cordova项目搭建
  5. FatFs 的用户层API接口应用简单介绍(基于STM32F1)
  6. sql在插入语句使用子查询_SQL插入查询
  7. Log4j屏蔽某个类的日志打印
  8. 《伸手系列》第二集-oracle数据库“灾难性”数据恢复-(一)
  9. 怎样使用NLPIR平台进行文本分析
  10. uniapp push 推送 个推 安卓Android添加Google 推送服务 FCM 离线推送 Dcloud