精选文章 JetPack WorkManager

JetPack WorkManager

作者:123_000000 时间: 2020-08-05 07:51:25
123_000000 2020-08-05 07:51:25

 

1.概览

官方文档:WorkManager
谷歌实验室:官方教程
官方案例:android-workmanager
WorkManger介绍视频:中文官方介绍视频

谷歌工程师博客:https://medium.com/androiddevelopers/workmanager-basics-beba51e94048

Android JetPack实例学习:https://www.jianshu.com/p/68e720b8a939

1.1  定义

使用 WorkManager API 可以轻松地调度即使在应用退出或设备重启时仍应运行的可延迟异步任务。

WorkManager, a compatible, flexible and simple library for deferrable background work.
WorkManger是一个可兼容、灵活和简单的延迟后台任务。

1.2 主要功能

最高向后兼容到 API 14

  • 在运行 API 23 及以上级别的设备上使用 JobScheduler
  • 在运行 API 14-22 的设备上结合使用 BroadcastReceiver 和 AlarmManager

 

  • 添加网络可用性或充电状态等工作约束
  • 调度一次性或周期性异步任务
  • 监控和管理计划任务
  • 将任务链接起来
  • 确保任务执行,即使应用或设备重启也同样执行任务
  • 遵循低电耗模式等省电功能

WorkManager 旨在用于可延迟运行(即不需要立即运行)并且在应用退出或设备重启时必须能够可靠运行的任务。例如:

  • 向后端服务发送日志或分析数据
  • 定期将应用数据与服务器同步

WorkManager 不适用于应用进程结束时能够安全终止的运行中后台工作,也不适用于需要立即执行的任务。请查看后台处理指南,了解哪种解决方案符合您的需求。

2. 使用入门

2.1 添加依赖

   dependencies {
      def work_version = "2.3.4"
        // (Java only)
        implementation "androidx.work:work-runtime:$work_version"
        // Kotlin + coroutines
        implementation "androidx.work:work-runtime-ktx:$work_version"
   }

2.2 方法指南

WorkManager 中几个重要类

Worker创建后台任务,定义工作单元。继承Worker,复写doWork() ,实现需要执行代码。
WorkRequest定义工作得运行方式和时间,以及任务在运行时应遵循得约束。
WorkManager将任务 (WorkRequest) 提交给系统执行。

 

工作流程下图:

JetPack WorkManager1

  1. WorkRequet创建完成后,InterTaskExecutor立即将它保存到WorkManager数据库中。
  2.  当满足WorkRequest的约束条件(Constaraints) 时(可以立即),Internal TaskExecutorr告诉WorkerFactory创建一个Worker。
  3. 从主线程调用worker的doWork()方法

2.2.1 Worker

  • 无变量(清理缓存)
class CleanUpWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
   
   override fun doWork(): Result {
        // ... 省略
        return try {
            // 删除逻辑
            // ...代码省略
            // 成功时返回
            Result.success()
        } catch (exception: Exception) {
            // 失败时返回
            Result.failure()
        }
    }
}
  • 任务的输入输出(需要同worker进行数据交互)

注意:下面实例中,使用Data参数传递,Data 对象应该很小,值可以是字符串、基元类型或数组变体。Data 对象的大小上限为10kb。如果需要将更多数据传入和传出Worker,应该将数据放在其他位置,例如 Room 数据库

返回结果,会通知WorkManager任务:

  • 已成功完成:Result.success()
  • 已失败:Result.failure()
  • 需要稍后重试:Result.retry()

传入本地图片地址,将图片上传,并返回url地址:

class UploadWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {

    override fun doWork(): Result {
        try {
            // Get the input  获取传入图片地址 *****
            val imageUriInput = inputData.getString(Constants.KEY_IMAGE_URI)

            // Do the work  图片上传
            val response = upload(imageUriInput)

            // Create the output of the work 
            val imageResponse = response.body()
            val imgLink = imageResponse.data.link

            // workDataOf (part of KTX) converts a list of pairs to a [Data] object.
            // 返回图片url *****
            val outputData = workDataOf(Constants.KEY_IMAGE_URI to imgLink)

            return Result.success(outputData)

        } catch (e: Exception) {
            return Result.failure()
        }
    }

    fun upload(imageUri: String): Response {
        TODO(“Webservice request code here”)
        // Webservice request code here; note this would need to be run
        // synchronously for reasons explained below.
    }

}

2.2.2  WorkRequest

//创建周期任务,定时每15天,清理缓存
var clearRequest = PeriodicWorkRequestBuilder(15, TimeUnit.DAYS).build()

//创建约束条件
val constraints = Constraints.Builder()
            .setRequiresBatteryNotLow(true)    //设备电量处于充足
            .setRequiredNetworkType(NetworkType.CONNECTED)  //网络状态约束(网络连接正常)
            .setRequiresCharging(true)   //设备充电时才能执行
            .setRequiresStorageNotLow(true) //设备储存充足
            .setTriggerContentMaxDelay(15,TimeUnit.DAYS)//设置从第一次检测到内容更改到计划的时间所允许的最大延迟
            .setTriggerContentUpdateDelay(15,TimeUnit.DAYS)//设置从第一次检测到内容更改到计划的时间所允许的延迟
            .build()



// 创建单次任务,图片上传获取url,传入本地图片地址
// define the input
val imageData = workDataOf(Constants.KEY_IMAGE_URI to imageUriString)

val uploadWorkRequest = OneTimeWorkRequestBuilder()
            .setInputData(imageData)               //定义任务的输入输出
            .setInitialDelay(10,TimeUnit.MINUTES)  //初始延迟
            .setConstraints(constraints)           //添加约束条件
            .setBackoffCriteria(                   //自定义退避延迟时间和政策
                BackoffPolicy.LINEAR,
                OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                TimeUnit.MILLISECONDS)
            .addTag("upload")                      //标记工作
            .build()
  • 创建任务类型
PeriodicWorkRequest多次、周期性任务请求,不支持任务链
OneTimeWorkRequest只执行一次的任务请求,支持任务链
  • 添加任务约束
  •  初始延迟
  • 定义任务的输入输出

 轻量级数据可使用Data进行传递
       val imageData = workDataOf(KEY_IMAGE_URI to imageUriString)
       val imageData = Data.Builder().putString(KEY_IMAGE_URI, imageUriString).build()

  • 重试和退避政策

当worker执行结果为Result.retry(),系统会根据默认的退避延迟时间和政策重新调度您的工作。退避延迟时间指定了重试工作前的最短等待时间。退避政策定义了在后续重试过程中,退避延迟时间随时间以怎样的方式增长;默认情况下按 EXPONENTIAL 延长可以通过BackoffCriteria来自定义退避延迟时间和政策。

  • 标记工作

通过为 WorkRequest 分配标记字符串,按逻辑对任务进行分组。这样就可以对使用特定标记的所有任务执行操作。
例如,
WorkManager.cancelAllWorkByTag(String) :取消使用特定标记的所有任务
WorkManager.getWorkInfosByTagLiveData(String) :返回 LiveData 和具有该标记的所有任务的状态列表。

2.2.3 WorkManager

  • 单任务执行
workManager.enqueue(clearRequest )
  • 链接工作

多任务时,使用WorkManager创建工作链并为其排队。工作链指定多个关联任务并定义任务的执行顺序。

 //当filter1三个全部执行完成之后,执行compress,然后upload
 WorkManager.getInstance(myContext)
        // Candidates to run in parallel
        // 多任务时并行运行
        .beginWith(listOf(filter1, filter2, filter3))
        // Dependent work (only runs after all previous work in chain)
        //从属任务(仅在链中所有先前工作之后运行)
        .then(compress)
        .then(upload)
        // Don't forget to enqueue()
        .enqueue()


WorkManager.getInstance()
        .beginUniqueWork(
             uniqueWorkName,       //唯一工作序列名称
             ExistingWorkPolicy,   //冲突解决策略
             requestA)                
        .then(requestB)
        .then(requestC)
        .enqueue();


 /**
   * enqueueUniqueWork:通过此方法设定一次只能激活一个特定名称的后台任务
   * singleWork:进行此操作的唯一名称,之后状态监听要获取此名称
   * ExistingWorkPolicy:工作策略(REPLACE:取消现有的序列并用新序列替换   KEEP:保持现有顺序并忽略新的请求   APPEND:将新序列附加到现有学列,在现有序列的最后一个任务完成后运行新序列的第一个任务)
   * request:自行构建的一次性任务或者周期性任务
   * 如何监听此任务状态,上述有代码
   */
    WorkManager.getInstance().enqueueUniqueWork("uniqueWorkName", ExistingWorkPolicy, request);
beginWith()开启链式任务,任务允许重复。
beginUniqueWork()开启链式任务,任务禁止重复。如需创建一个唯一工作链时使用

注意:WorkerManager要求必须在前一个后台任务运行成功后,下一个后台任务才会运行,也就是说,如果某个后台任务运行失败,或者被取消了,那么接下来的后台任务就都得不到运行了。

uniqueWorkName:唯一工作链名称,在状态监听时

ExistingWorkPolicy:它指定了如果已经存在一个具有该唯一名称的未完成工作链时,如何解决冲突

REPLACE取消现有工作链,并将其 REPLACE 为新工作链。
KEEPKEEP 现有序列并忽略您的新请求。
APPEND将新序列 APPEND 到现有序列,在现有序列的最后一个任务完成后运行新序列的第一个任务。您不能将 APPEND 与 PeriodicWorkRequest 一起使用。

2.3 工作状态和观差工作

2.3.1工作状态

工作生命周期,不同的State标识。观察LiveData 时,您会看到这些状态。

JetPack WorkManager2

BLOCKED如果有尚未完成的前提性工作
ENQUEUED如果work能够能够在满足Constrains和时机条件后立即运行
RUNNING当work处于活跃执行时
SUCCESSED

返回Result.success(),终止State,只有OneTimeWorkRequest可以进入这种State

返回Result.fail(),终止State,所有依赖工作也会被标记,并且不会运行,只有OneTimeWorkRequest可以进入这种State。

CANCELLED取消尚未终止的WorkRequest,进入此状态,所有依赖工作也会被标记,且不会运行

2.3.2 观差工作

将工作加入队列后,您可以通过 WorkManager 检查其状态。相关信息在 WorkInfo 对象中提供,包括工作的 id、标签、当前 State 和任何输出数据。

获取WorkInfo方式:

JetPack WorkManager3

Request Id 对于特定的 WorkRequest,您可以利用 WorkManager.getWorkInfoById(UUID) 或 WorkManager.getWorkInfoByIdLiveData(UUID) 来通过 WorkRequest id 检索其 WorkInfo。
Request Tag对于指定的标记,您可以利用 WorkManager.getWorkInfosByTag(String) 或 WorkManager.getWorkInfosByTagLiveData(String) 检索所有匹配的 WorkRequest 的 WorkInfo 对象。
UniqueName(唯一工作名称)对于唯一工作名称,您可以利用 WorkManager.getWorkInfosForUniqueWork(String) 或 WorkManager.getWorkInfosForUniqueWorkLiveData(String) 检索所有匹配的 WorkRequest 的 WorkInfo 对象。

 

// In your UI (activity, fragment, etc)
//通过request id 监听单个任务执行状态
WorkManager.getInstance().getWorkInfoByIdLiveData(uploadWorkRequest.id)
        .observe(lifecycleOwner, Observer { workInfo ->
            // Check if the current work's state is "successfully finished"
            if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
                displayImage(workInfo.outputData.getString(KEY_IMAGE_URI))
            }
        })


//通过Tag标签监听同一标签下所有后台任务请求的运行结果
WorkManager.getInstance().getWorkInfosByTagLiveData("upload")
       .observe(lifecycleOwner, Observer { workInfo->
            //遍历所有tag标签的workInfo
            for (WorkInfo workInfo : workInfos) {
              if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) {
                   displayImage(workInfo.outputData.getString(KEY_IMAGE_URI))
               }
            }
       })


// 如果是通过enqueueUniqueWork(“workName")执行
WorkManager.getInstance().getWorkInfosForUniqueWorkLiveData("workName")
       .observe(lifecycleOwner, observer { workInfo->
            for (WorkInfo workInfo : workInfos) {
               if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) {
                    displayImage(workInfo.outputData.getString(KEY_IMAGE_URI))
                 }
            }
        })

注意:

  •  每个WorkRequset都有一个唯一id (由WorkManager自动生成),并且该唯一ID是查找关联的WorkInfo的一种方法。
  • 利用每个方法的LiveData变量,您可以通过注册监听器来观察 WorkInfo 的变化。例如上面实例,想要在图片上传成功后向用户显示上传后得到的url。

 

勿删,copyright占位
分享文章到微博
分享文章到朋友圈

上一篇:解决 No converter found for return value of type 的问题

下一篇:js操作Date类

您可能感兴趣

  • Box 黑科技 —— 支持手机端反编译 !

    项目地址: Box 文末扫码获取最新安装包 。 前言 有将近一个月没有更新文章了,一方面在啃 AOSP ,消化起来确实比较慢。在阅读的过程中,有时候上来就会陷入源码细节,其实这是没有必要的。刚开始更多的应该从整体脉络上去理解,摸清整个流程之后再去有针对性的看某些细节,才会事半功倍。下一篇应该会带来 Activity 启动流程分析 。 除了啃 AOSP 之外,剩下的时间都花在了开源项目的维护和...

  • 使用虚拟机对Nvidia Jetson TX2刷机安装

    1.主机和TX2局域网设置:使用路由器使主机和TX2在一个局域网内,也可以使用wifi但我使用的wifi下载太慢,容易出错,建议使用路由器。两者的IP可以设置成动态也可以手动设置成静态。这里为省时设置成自动的。 虚拟机ubuntu1604系统,设置成桥接模式,ip也是设置成自动获取的,也可以自动设置,自动获取也可以相互ssh,就简单设置成自动获取。 2.下载JetPack-L4T-3.3-l...

  • 从TX2 到 配置pip、cmake、OpenCV、tensorflow、Tensorflow Object Detection API

    本博客只适合 jetpack3.3刷的Ubuntu16.04。。如果是最新的 jetpack4.2 刷的 Ubuntu18.04,不适应。。亲测 1、tx2 安装 pip 和 cmake 由于用官方刷机教程 jetpack 刷机后,tx2的系统虽然有python 3.5+和python 2.7,但却没有pip和cmake的,而要安装后续的库或者编译库的话,就需要以上两个工具的,所以,第一步需...

  • WorkManager 进阶课堂 | AndroidDevSummit 中文字幕视频

    WorkManager 的影响绝不仅仅限于应用本身。在本次 Android 开发者峰会上,Sumir Kataria 和 Rahul Ravikumar 为大家详细讲解了 WorkManager 的运行机制,以及在日常开发中大家常常不慎落入的 "陷阱"。相信在看完他们的分享后,您能用更宏大的视角解读和处理 Android 后台任务。 腾讯视频链接 https://v.qq.com/x/pag...

  • SpringBoot中如何灵活的实现接口数据的加解密功能?

    数据是企业的第四张名片,企业级开发中少不了数据的加密传输,所以本文介绍下SpringBoot中接口数据加密、解密的方式。 本文目录 一、加密方案介绍二、实现原理三、实战四、测试五、踩到的坑 一、加密方案介绍 对接口的加密解密操作主要有下面两种方式: 自定义消息转换器 优势:仅需实现接口,配置简单。 使用spring提供的接口RequestBodyAdvice和ResponseBodyAdvi...

  • (一百八十九)Android Jetpack 学习(一)

    前言:老大让学习点新的东西分享一下,本来看了WiFi的电量统计,看到最后感觉挺没意思的,然后就翻bos直聘看有什么新技术要求的,看到flutter,Jetpack、react native。。。Jetpack这个比较新,学习下Jetpack 参考: https://developer.android.google.cn/jetpack https://developer.android.go...

  • 6. Jetpack---Paging你知道怎样上拉加载吗?

    code小生,一个专注大前端领域的技术平台 公众号回复 Android 加入我的技术群 作者:Hankkin链接:https://juejin.im/post/5d63f620f265da03970bc76d声明:本文已获Hankkin投稿发表,转发等请联系原作者授权 之前的几篇源码分析我们分别对Navigation、Lifecycles、ViewModel、LiveData、进行了分析,也...

  • Android Jetpack 之 LifeCycle

    1. Jetpack Jetpack 是一套库、工具和指南的集合,并不是一个框架或者组件。Jetpack 包含与平台 API 解除捆绑的 androidx.* 软件包库。Android Jetpack 组件是库的集合,这些库是为协同工作而构建的,不过也可以单独采用,可全部使用,也可混合搭配!Lifecycle 就是 Android Jetpack 组件之一。 2. Lifecycle Lif...

华为云40多款云服务产品0元试用活动

免费套餐,马上领取!
CSDN

CSDN

中国开发者社区CSDN (Chinese Software Developer Network) 创立于1999年,致力为中国开发者提供知识传播、在线学习、职业发展等全生命周期服务。