Jetpack学习之WorkManager

2023-10-26

绝大部分应用程序都有在后台执行任务的需求,根据需求的不同,Android为后台任务提供了多种解决方案,如JobScheduler、Loader、Service等。WorkManager为应用程序中那些不需要及时完成的任务提供了一个统一的解决方案,以便在设备电量和用户体验之间达到一个比较好的平衡。

WorkManager的3个重要特点:

  1. 针对的是不需要及时完成的任务
  2. 保证任务一定会被执行
  3. 兼容范围广。最低能兼容API Level 14

WorkManager的兼容方案:
WorkManager能依据设备的情况,选择不同的执行方案,在API Level 23以上的设备中,通过JobScheduler完成任务;在API Level 23以下的设备中,通过AlarmManager+BroadcastReceiver组合来完成任务,但无论采用哪种方案,任务最终都是交由Executor来执行的。

使用方法
  1. 添加依赖
    在app的build.gradle中添加依赖
implementation 'androidx.work:work-runtime:2.4.0'
  1. 使用Worker类定义任务
    新建一个名为MyWorker的类,继承自Worker类,并且覆盖都doWork()方法,所有需要在任务中执行的代码都在该方法中进行编写。
class MyWorker(context: Context, params: WorkerParameters): Worker(context, params) {

    override fun doWork(): Result {
        return Result.success()
    }
}
doWork()方法有3种类型的返回值
- 若执行成功,则返回Result.success()
- 若执行失败,则返回Result.failure()
- 若需要重新执行,则返回Result.retry()
  1. 使用WorkRequest配置任务
  • 设置任务触发条件
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .setRequiresCharging(true)
            .setRequiresBatteryNotLow(true)
            .build()
  • 将任务触发条件设置到WorkRequest
    WorkRequest是一个抽象类,它有两种实现方式——OneTimeWorkRequest和PeriodicWorkRequest,分别对应的是一次性任务和周期性任务。
        val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
            .setConstraints(constraints)
            .build()
  • 设置延迟执行时间
        val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
            .setConstraints(constraints)
            //延迟10分钟后执行
            .setInitialDelay(10, TimeUnit.MINUTES)
            .build()
  • 设置指数退避策略
    假如Worker线程的执行出现了异常,希望过一段时间后重试该任务,那么可以在Worker的doWork()方法种返回Result.retry(),系统会有默认的指数退避策略来进行重试,也可以通过setBackoffCriteria()方法来自定义指数退避策略。
        val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
            .setConstraints(constraints)
            .setBackoffCriteria(BackoffPolicy.LINEAR, 10, TimeUnit.MINUTES)
            .build()
  • 为任务设置tag标签
        val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
            .setConstraints(constraints)
            .addTag("MyWorkerTag")
            .build()
  1. 将任务提交给系统
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)
  1. 观察任务的状态
    任务提交给系统后,可以通过WorkInfo获知任务的状态。WorkInfo包含任务的id、tag、Worker对象传递过来的outputData,以及任务的当前状态。有3种方法可以得到WorkInfo对象:
  • WorkManager.getInstance(this).getWorkInfoById(oneTimeWorkRequest.id)
  • WorkManager.getInstance(this).getWorkInfosByTag(“MyWorkerTag”)
  • WorkManager.getInstance(this).getWorkInfosForUniqueWork(“uniqueWorkName”)
    如果希望实时获取任务状态,三个方法还有对应的LiveData方法:
  • WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
  • WorkManager.getInstance(this).getWorkInfosByTagLiveData(“MyWorkerTag”)
  • WorkManager.getInstance(this).getWorkInfosForUniqueWorkLiveData(“uniqueWorkName”)

通过LiveData可以在任务状态发生变化收到通知:

        WorkManager.getInstance(this)
            .getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
            .observe(this, {
                workInfo -> Log.d("onChanged", "workInfo: $workInfo")
            })
  1. 取消任务
WorkManager.getInstance(this).cancelAllWork()
  1. WorkManager与Worker之间的参数传递
    WorkManager通过setInputData()方法想Worker传递数据。数据的传递通过Data对象来完成。需要注意的是,Data只能用于传递一些小的基本类型的数据,且数据最大不能超过10KB。
    Worker通过getInputData()方法接收数据,并在任务完成后,向WorkManager返回数据。
        val inputData = Data.Builder().putString("input_data", "My Worker Data").build()
        val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
            .setConstraints(constraints)
            .setInputData(inputData)
            .build()
    override fun doWork(): Result {
        //接收外面传递进来的数据
        val inputData = inputData.getString("input_data")
        //任务执行完成后返回数据
        val outputData = Data.Builder().putString("output_data", "Success").build()
        return Result.success(outputData)
    }

WorkManager通过LiveData得到从Worker返回的数据。

WorkManager.getInstance(this)
            .getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
            .observe(this, { workInfo ->
                run {
                    if (workInfo?.state == WorkInfo.State.SUCCEEDED) {
                        val outputData = workInfo.outputData.getString("output_data")
                        Log.d("onChanged", "outputData: $outputData")
                    }
                }
            })
  1. 周期性任务PeriodicWorkRequest
    周期性任务会按照设定的时间定期执行,间隔时间不能少于15分钟。
        val periodicWorkRequest = PeriodicWorkRequest.Builder(MyWorker::class.java, 20, TimeUnit.MINUTES)
            .setConstraints(constraints)
            .addTag("Periodic MyWorker")
            .build()
  1. 任务链
    如果有一系列的任务需要按顺序执行,那么可以利用WorkManager.beginWith().then().then()…enqueue()的方式构建任务链。
WorkManager.getInstance(this).beginWith(oneTimeWorkRequest1).then(oneTimeWorkRequest2).enqueue()

假设有更复杂的任务链,还可以考虑用WorkContinuation.combine()方法将任务链组合起来。

        val workContinuation1 =
            WorkManager.getInstance(this).beginWith(oneTimeWorkRequest1).then(oneTimeWorkRequest2)
        val workContinuation2 =
            WorkManager.getInstance(this).beginWith(oneTimeWorkRequest3).then(oneTimeWorkRequest4)
        val taskList = mutableListOf(workContinuation1, workContinuation2)
        WorkContinuation.combine(taskList).then(oneTimeWorkRequest5).enqueue()
  1. 结论
    WorkManager会根据系统的版本,决定采用JobSheduler或AlarmManager+BroadcastReceiver来完成任务。但这些API很可能会收到非原生系统的影响。
    同时周期性任务的实际执行时间,与所设定的时间差别较大,并且没有明显的规律。在任务执行完成后,WorkInfo并不会收到Success的通知。Android认为Success和Failure都属于“终止类”的通知,意味着,若发出此类通知,则表明任务“彻底终止”,而周期性任务是不会彻底终止的,它会一直执行下去,因此使用LiveData观察周期性任务时,不会 收到Success这一类的通知。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jetpack学习之WorkManager 的相关文章

  • 如何在android中的视频视图中获取视频的总长度

    我有一个问题 我想获取在视频视图中运行的视频的总长度 为此我正在使用视频视图的 getDuration 方法 但当我将其与 currentPosition 进行比较时 它总是返回 1 实际上我希望如果视频的当前位置等于视频的总长度那么它应该
  • Android + XAMARIN + 强制屏幕保持“纵向”模式(使用 AndroidManifest)

    我在这里阅读了这个问题的一些答案 但不知何故我无法让它发挥作用 我的 AndroidManifest xml 如下所示
  • 如何引导用户为我的应用程序启用辅助功能服务

    我知道不可能以编程方式启用应用程序的辅助功能服务 因此我想将用户引导至此屏幕 System settings gt Accessibility gt app name gt enable disable screen 那可能吗 您可以将它们
  • 使用 hisorian.py 时显示“找不到结束时间”

    我正在尝试收集我的应用程序的电池统计信息 运行指定的所有命令后http developer android com tools performance batterystats battery historian index html ht
  • audioTrack play() 只播放一次

    第一次使用Android的AudioTrack 我创建了一个 AndroidAudioDevice 类 我用这个构造函数初始化它 public AndroidAudioDevice constructor Log i Audio const
  • 如何使用Android读取Service中的加速度计数据

    通常 在 Android 中 我们通过重写 OnSensorChanged 函数来读取 Activity 中的加速度计数据 我很好奇我们如何在 服务 中做到这一点 谢谢 文森特 实际上OnSensorChanged SensorEvent
  • API 级别 15 的印地语字体(又名 Android 4.0.2)

    我有一个基于印地语内容的 Android 应用程序 并使用了 Android API 16 SDK 中的 devangiri 字体 并重命名为印地语 ttf 文本在 API 级别 16 和 17 上渲染良好 但在 Android API 级
  • 如何在屏幕上动态移动 Textview? (框架布局)

    我有一个应用程序 可以在屏幕上的 FrameLayout 上显示相机视图 屏幕处于固定风景模式 我需要编写一个带有动态确定的屏幕坐标的textView 坐标以百分比确定 例如 将文本视图写入屏幕坐标 x 80 y 20 屏幕上 将文本视图写
  • Android SDK 中缺少 Gradle(使用 cordova + ionic)

    是的 我搜索了这个 但没有搜索到任何内容 只是有关 ANDROID HOME 路径的信息 但就我而言 我认为这不是真正的问题 当我尝试做的时候ionic build android我收到这个错误 错误 在 android sdk 中找不到
  • Android - GC 滞后于列表视图滚动“更大”的图像

    在列表视图中 我想在列表条目上绘制一个图像 这 20 张图像必须缩放以填充垂直模式的宽度 手机分辨率为 480 x 800 像素 SGS2 图像分辨率为 400x400 大小约为 100KB 我已将图像放在可绘制文件夹中 当我滚动列表时 它
  • 从服务(IntentService)和活动执行的AsyncTask - 有区别吗?

    从 Activity 或 IntentService 启动 AsyncSync 之间有什么区别吗 我正在构建一个通过 http 下载和上传文件的应用程序 我为每次传输使用带有进度条的自定义通知布局 我选择并行传输或将它们放入队列 您会推荐哪
  • 如何布局文本以围绕图像流动

    你能告诉我是否有一种方法来布局文本 围绕图像 像这样 text text text text text text text text text text text text text text text text text 我已经收到一位
  • Android - 获取所有可用存储的列表

    我正在从互联网将数据下载到我的应用程序中 如果我指定内部内存 Environment getExternalStorageDirectory 我可能会遇到 空间不足 的问题 SD卡安装地址总是因手机而异 所以我想允许用户选择他喜欢的位置 在
  • 将 Android 应用程序与服务器上的 Matlab 应用程序连接

    我正在 Android 上开发一个应用程序 它将获取图像输入 并将该输入传递到安装 MATLAB 应用程序的服务器 MATLAB 应用程序将计算结果并将其返回到该 Android 应用程序 我想知道我可以使用哪个服务器 如何将 MATLAB
  • RecyclerView OnClick 位置

    我正在尝试获取我的点击项目的位置RecyclerView 然而 这有点奇怪 只让我在点击时记录位置 而不让我做一个Toast的位置 看这里 public class MainAdapter extends RecyclerView Adap
  • 在Android Dialog中,如何为startActivityForResult设置onActivityResult?

    从活动中 我可以轻松设置onActivityResult 并打电话startActivityForResult 一切正常 现在 我需要打电话startActivityForResult 从对话框中 但我无法设置onActivityResul
  • registerForActivityResult TakePicture 未触发

    我尝试使用新的 registerForActivityResult 来拍照 我可以打开相机意图 但拍照后 未触发回调 并且我在 logcat 上看不到任何有关 Activity Result 或错误的信息 我也尝试了RequestPermi
  • Android相对布局放置问题

    我在 XML 中为列表项创建相对布局以用于 ListView 中的一系列项目时遇到问题 我已经尝试了几个小时 并且正在撕扯我的头发 试图让它看起来像我想要的那样 但无法让所有东西都出现在正确的位置 而不是重叠或错位 我可以获取第一张图像和接
  • 如何消除按钮和其他视图之间的额外间隙?

    当我创建按钮视图时 Android 总是在该按钮与其下方的其他视图之间创建一些额外的空间 在下面的示例中 第二个按钮上方有一个按钮 您可以看到这两个按钮之间的间隙 我怎样才能摆脱这个差距 谢谢
  • Android 并获取 id 转换为字符串的视图

    在 Android 项目的 Java 代码中 如果您想要视图资源的引用 您可以执行以下操作 View addButton findViewById R id button 0 在上面的 R id button 0 不是一个字符串 是否可以通

随机推荐

  • 在树莓派中安装ROS系统(Kinetic)

    在树莓派中安装ROS系统 重新梳理了一下树莓派的安装流程 现在我们来开始吧 打开官网教程 http wiki ros org kinetic step1 安装源 中国 sudo sh c etc lsb release echo deb h
  • 物联网+区块链溯源方案

    物联网硬件 蓝牙 wifi 加区块链的方式可有效对现实世界中的实例进行链上映射 本文介绍一种基于硬件的轮胎区块链防伪溯源以及渠道管控的方案思路 更多区块链技术与应用分类 区块链应用 区块链开发 以太坊 Fabric BCOS 密码技术 共识
  • 服务器搭建系列之7:k8s安装postgresql数据库,2022最新版本

    Dockerfile FROM postgres EXPOSE 5432 deploy yaml 命名空间 apiVersion v1 kind Namespace metadata name fandai apiVersion apps
  • Maven安装与配置,Eclipse配置Maven【图文并茂的保姆级教程】

    Welcome Huihui s Code World 接下来看看由辉辉所写的关于Maven的相关操作吧 目录 Welcome Huihui s Code World 一 Maven是什么 二 Maven的下载 辉辉小贴士 maven中各个
  • Svm实现多分类

    机器学习 Svm实现多分类详解 Svm实现多类分类原理 代码实现 训练的图片 Svm实现多类分类原理 1 支持向量机分类算法最初只用于解决二分类问题 缺乏处理多分类问题的能力 后来随着需求的变化 需要svm处理多分类分为 目前构造多分类支持
  • 各种音视频编解码学习详解(11)--Flash Video系列

    用于在 Flash 中压缩视频 FLV流媒体格式是一种新的视频格式 它的出现有效地解决了视频文件导入Flash后 使导出的SWF文件体积庞大 不能在网络上有效使用等 缺点 一般FLV文件包在SWF PLAYER 的壳里 并且FLV可以很好的
  • Linux Memcached 安装

    1 Linux系统安装memcached 首先要先安装libevent库 memcache依赖于libevent 必须先安装 自动下载安装方式 也可使用源码安装方式 yum install libevent devel yum instal
  • 陪我到可可西里看一看海,不要未来,只要你来。——大冰 《陪我到可可西里去看海》

    陪我到可可西里看一看海 不要未来 只要你来 大冰 陪我到可可西里去看海
  • 斐波那契查找详细注解版

    对于斐波那契数列 1 1 2 3 5 8 13 21 34 55 89 也可以从0开始 前后两个数字的比值随着数列的增加 越来越接近黄金比值0 618 比如这里的89 把它想象成整个有序表的元素个数 而89是由前面的两个斐波那契数34和55
  • Python中RotatingFileHandler、TimedRotatingFileHandler函数用法

    欢迎来到我的博客 作者 秋无之地 简介 CSDN爬虫 后端 大数据领域创作者 目前从事python爬虫 后端和大数据等相关工作 主要擅长领域有 爬虫 后端 大数据开发 数据分析等 欢迎小伙伴们点赞 收藏 留言 背景 在python开发过程中
  • Linux如何卸载软件

    Linux系统可以通过终端 Terminal 或图形界面 GUI 来卸载软件 终端方式可以使用apt get Ubuntu 或yum CentOS 命令来实现 而图形界面方式可以使用系统自带的软件管理器来实现 比如Ubuntu的Ubuntu
  • libev学习系列之二:libev下载

    libev学习系列之二 libev下载 版本说明 版本 作者 日期 备注 0 1 ZY 2019 5 31 初稿 目录 文章目录 libev学习系列之二 libev下载 版本说明 目录 官网 GitHub 我的某度网盘 官网 可以去官网下载
  • 【python练习题 03】高矮个子排队

    题目 现在有一队小朋友 他们高矮不同 我们以正整数数组表示这一队小朋友的身高 如数组 5 3 1 2 3 我们现在希望小朋友排队 以 高 矮 高 矮 顺序排列 每一个 高 位置的小朋友要比相邻的位置高或者相等 每一个 矮 位置的小朋友要比相
  • Date:January 29th Title: 集训Day2-小信小友打怪兽 题解

    时间 1s 空间 256M 题目描述 小信与小友一起组队打怪兽 有一个长度为n的怪兽序列 一些怪兽会对小信造成伤害 另一些不会 小友是大佬 所有怪兽都伤害不了他 小信与小友轮流打怪兽 小信先手 小友后手 他们需要按照顺序打怪兽 由于技能有冷
  • 小米盒子3s刷机为国际版系统android TV 8.0

    小米盒子3s刷机为国际版系统android TV 8 0 所需工具和软件 一个U盘 adb工具 使用adb工具 通过ip连接小米盒子 官方下载地址 点此进入 dump 16AB img MiBOX3S queenchristina r145
  • tera-PROMISE数据集

    tera Promise数据集 原网址 http openscience us repo 已经打不开 备份网址 https github com opensciences opensciences github io 来源 论文An Imp
  • 蓝桥杯历届试题——取球游戏(博弈论)

    取球游戏 今盒子里有n个小球 A B两人轮流从盒中取球 每个人都可以看到另一个人取了多少个 也可以看到盒中还剩下多少个 并且两人都很聪明 不会做出错误的判断 我们约定 每个人从盒子中取出的球的数目必须是 1 3 7或者8个 轮到某一方取球时
  • 文件对应的Content-Type类型

    https www cnblogs com liu heng p 7520564 html CONTENT TYPE load text html 123 application vnd lotus 1 2 3 3ds image x 3d
  • 海思Hi3559A平台移植 opencv4.0.0

    原文 https blog csdn net xclshwd article details 85257117 海思Hi3559A平台移植 opencv4 0 0 2018年12月26日 09 51 53 xclshwd 阅读数 370 版
  • Jetpack学习之WorkManager

    绝大部分应用程序都有在后台执行任务的需求 根据需求的不同 Android为后台任务提供了多种解决方案 如JobScheduler Loader Service等 WorkManager为应用程序中那些不需要及时完成的任务提供了一个统一的解决