Android WorkManager入门(二)

news2024/12/28 21:27:50

WorkManager入门

  • 上一篇
  • 前言
  • 创建 WorkRequest并提交 定时的任务(PeriodicWorkRequest)
  • 配合约束使用
  • 定义执行范围
  • 失败后的重试
  • 为WorkRequest打上TAG
    • 其他取消方法
  • 传参和返回参数
  • 总结
  • 参考资料


上一篇

Android WorkManager入门(一)

前言

在当今快节奏的生活中,移动设备已经成为我们日常工作和生活不可或缺的一部分。然而,随着应用程序的复杂性不断增加,开发人员面临着一个重要的挑战:如何在后台执行任务,而不会影响用户的体验和设备的性能?
在过去,开发人员通常使用传统的后台服务或定时任务来解决这个问题。然而,这些方法往往很复杂,需要大量的代码和资源,并且很难管理和调度任务。幸运的是,谷歌最近推出了一个新的解决方案:安卓WorkManager。
安卓WorkManager是一个灵活、强大的后台任务调度库,旨在帮助开发人员轻松管理和执行后台任务。它提供了一种简单的方式来调度任务,无论是一次性任务、定期任务还是延迟任务,都可以很容易地实现。同时,WorkManager还提供了一系列强大的功能,如任务链、约束条件和灵活的重试机制,以确保任务能够在最佳的时间和条件下执行。
在本文中,我们将深入探讨安卓WorkManager的原理和用法,并通过实际示例演示如何使用它来解决常见的后台任务问题。无论您是一名初学者还是一名有经验的开发人员,本文都将为您提供宝贵的知识和实用的技巧,帮助您更好地利用安卓WorkManager来优化您的应用程序。让我们一起开始这段关于安卓WorkManager的探索之旅吧!

好吧,不多BB,其实是因为安卓12以上想起后台服务必须要悬浮窗权限,想起还有个WorkManager这种东西,去官网学习然后总结一下。没有看入门一的可以先看一,或者看官网的也可以。

创建 WorkRequest并提交 定时的任务(PeriodicWorkRequest)

我们可能要定期备份数据、定期下载应用中的新鲜内容或者定期上传日志到服务器。就可以使用PeriodicWorkRequest

在使用之前我们除了接入依赖还需要新建一个worker

import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class MyWorker(appContext: Context, workerParams: WorkerParameters):Worker(appContext, workerParams) {
    companion object{
        private const val TAG = "MyWorker"
    }


    override fun doWork(): Result {

        Log.d(TAG, "doWork: 我正在做一些工作")

        return Result.success()
    }

}

然后我们在需要使用的地方加上下例代码:

 val mWorkerRequest4 =
            PeriodicWorkRequestBuilder<MyWorker>(1, TimeUnit.HOURS)
                .build()

        //通过WorkManager提交WorkRequest,执行MyWorker
        WorkManager
            .getInstance(this)
            .enqueue(mWorkerRequest4)
            

可以定义的最短重复间隔是 15 分钟(与 JobScheduler API 相同)。

然后我们运行项目,等待一小时…

在这里插入图片描述

ok,一分钟过去了,然后我们发现一跑起来其实就有日志输出了,所以这个时间其实是最小间隔时间,和setInitialDelay的延时是不一样的。

配合约束使用

这时我们加上一个约束,这时代码变成了下例这样:

	val constraints = Constraints.Builder()
            .setRequiresCharging(true)
            .build()
	 val mWorkerRequest4 =
            PeriodicWorkRequestBuilder<MyWorker>(1, TimeUnit.HOURS)
                .setConstraints(constraints)
                .build()

        //通过WorkManager提交WorkRequest,执行MyWorker
        WorkManager
            .getInstance(this)
            .enqueue(mWorkerRequest4)

setRequiresCharging(true)标水充电时执行,如果不充电,那么这个定时任务就不会执行。不然就会像第一个例子一样,定时任务一开始就执行了。

定义执行范围

这是官方在每小时的最后 15 分钟内运行的定期工作的示例:

  //每小时的最后 15 分钟内运行的定期工作
        val mWorkerRequest5 =
            PeriodicWorkRequestBuilder<MyWorker>(
            1, TimeUnit.HOURS, // 执行周期
            15, TimeUnit.MINUTES) // 实际执行时间
            .build()


        //通过WorkManager提交WorkRequest,执行MyWorker
        WorkManager
            .getInstance(this)
            .enqueue(mWorkerRequest5)

结合这张图可以更好地理解两个时间在这里插入图片描述

RequiresApi最低为26

失败后的重试

后台任务有失败的可能,所以在Worker的doWork方法的返回值中给我们提供了三种方法,分别是:

  • Result.success()成功
  • Result.failure()失败
  • Result.retry()重试

成功和失败都是定性的,但是重试这个东西应该是会再执行的,那么怎么执行呢,我们看下面这个例子:

首先,我们将MyWorker改为下面这个样子:

import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class MyWorker(appContext: Context, workerParams: WorkerParameters):Worker(appContext, workerParams) {
    companion object{
        private const val TAG = "MyWorker"
    }


    override fun doWork(): Result {

        Log.d(TAG, "doWork: 我正在做一些工作")
        val doWorkFail = true
        if (doWorkFail){
            Log.d(TAG, "doWork: 我失败了,重试一下")
            return Result.retry()
        }

        return Result.success()
    }

}

然后再使用 setBackoffCriteria 方法对回退的工作进行处理:

  val mWorkerRequest6 = OneTimeWorkRequestBuilder<MyWorker>()
            .setBackoffCriteria(
                BackoffPolicy.LINEAR,
                MIN_BACKOFF_MILLIS,
                TimeUnit.MILLISECONDS)
            .build()


        //通过WorkManager提交WorkRequest,执行MyWorker
        WorkManager
            .getInstance(this)
            .enqueue(mWorkerRequest6 )

setBackoffCriteria 有一些参数,我们来看下都是什么

  • BackoffPolicy 指定回退时间策略;政策为 LINEAR,每次尝试重试时,重试间隔都会增加约 10 秒。例如,第一次运行以 Result.retry() 结束并在 10 秒后重试;然后,如果工作在后续尝试后继续返回 Result.retry(),那么接下来会在 20 秒、30 秒、40 秒后重试,以此类推。如果退避政策设置为 EXPONENTIAL,那么重试时长序列将接近 20、40、80 秒,以此类推。
    在这里插入图片描述
  • backoffDelay + timeUnit 具体的时间,最小为10s,在WorkRequest中有定义
    在这里插入图片描述
    我们跑起来看下效果:
    在这里插入图片描述
    结果如下
    在这里插入图片描述

为WorkRequest打上TAG

我们可以在使用中为WorkRequest打上Tag,这样就可以通过WorkManager.cancelAllWorkByTag(String) 取消带有特定标记的所有工作请求,或者用WorkManager.getWorkInfosByTag(String) 返回一个 WorkInfo 对象列表,该列表可用于确定当前工作状态。

来看下例代码:

 val mWorkerRequest7 = OneTimeWorkRequestBuilder<MyWorker>()
            .addTag("myWorker")
            .setInitialDelay(12, TimeUnit.MINUTES)
            .build()
//通过WorkManager提交WorkRequest,执行MyWorker
        WorkManager
            .getInstance(this)
            .enqueue(mWorkerRequest7)

        Handler().postDelayed({
            val workInfosByTag = WorkManager.getInstance(this).getWorkInfosByTag("myWorker")
            Log.d(TAG, "testWorkManager: ${workInfosByTag.get()}")

            Log.d(TAG, "testWorkManager: ${WorkManager.getInstance(this).cancelAllWorkByTag("myWorker").result}")
            WorkManager.getInstance(this).cancelAllWorkByTag("myWorker")
            WorkManager.getInstance(this).cancelAllWorkByTag("myWorker1").state.observe(this) {
                Log.d(TAG, "testWorkManager: $it")
            }
        },10*1000L)

通过日志我们可以看到确实可以通过tag找到执行的work,但是并不能取消,还是执行了

2024-01-18 10:35:26.130 22739-22739 MainActivity            com.example.test                     D  testWorkManager: [WorkInfo{mId='17366cc4-fa74-4d42-98d9-9b4e845fb19e', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='4c902568-aab9-4a96-b7e5-eccc93eea99c', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='708826dd-8e63-44f2-9311-746b15140bac', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='79e954b7-9318-4d7c-bd67-b8fd0e810479', mState=SUCCEEDED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='7fb339e0-6acc-4b64-b451-ec1c9b82aaa6', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='87938938-1fb9-4304-afd3-bff71716a187', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='9233f46d-0cd4-48d7-9d05-e504bf46d623', mState=ENQUEUED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='a55eb79b-b0b0-4e84-8a46-436056c6a8a7', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='a6f46271-e7f7-4f92-87bb-fa2d6e8b8ac2', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='d831ee89-d58f-4e7d-8994-4d0fc02370ea', mState=CANCELLED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}, WorkInfo{mId='dd3dca01-d868-465b-8efc-31256b06cc6b', mState=SUCCEEDED, mOutputData=Data {}, mTags=[myWorker, com.example.test.MyWorker], mProgress=Data {}}]
2024-01-18 10:35:26.131 22739-22739 MainActivity            com.example.test                     D  testWorkManager: androidx.work.impl.utils.futures.SettableFuture@ac1927[status=PENDING]
2024-01-18 10:35:26.133 22739-22739 MainActivity            com.example.test                     D  testWorkManager: IN_PROGRESS
2024-01-18 10:35:26.160 22739-22739 MainActivity            com.example.test                     D  testWorkManager: SUCCESS
2024-01-18 10:35:47.721 22739-23012 MyWorker                com.example.test                     D  doWork: 我正在做一些工作
2024-01-18 10:35:47.727 22739-22785 WM-WorkerWrapper        com.example.test                     I  Worker result SUCCESS for Work [ id=b0ba1ea9-8028-45ed-80a9-bb404a6f225c, tags={ com.example.test.MyWorker } ]

这是因为,已经在队列中等待执行的任务是不会被取消的,包括重试回退的任务;这里的cancel是周期性任务使用的,在下一次worker进入队列时生效

其他取消方法

请注意,所有取消方法都是尽力而为的

除了cancelAllWorkByTag,还有下面几个取消方法:

  • cancelWorkById 通过id取消

  • cancelUniqueWork 取消工作链中的工作,这个工作链我们后面进阶讲

  • cancelAllWork 取消所有工作

传参和返回参数

在使用WorkManager中,我们有一些场景需要在使用是传参,在return中返回参数,这时我们就需要使用到setInputData方法,接受一个workDataOf方法

在这里插入图片描述
示例代码如下:

        val mWorkerRequest8= OneTimeWorkRequestBuilder<MyWorker>()
            .addTag("myWorker")
            .setInputData(workDataOf( "MY_DATA" to "这是我传的参数"))
            .build()


        //通过WorkManager提交WorkRequest,执行MyWorker
        WorkManager
            .getInstance(this)
            .enqueue(mWorkerRequest8)



        WorkManager.getInstance(this).getWorkInfoByIdLiveData(mWorkerRequest8.id).observe(this) {
            Log.d(TAG, "testWorkManager: ${it.outputData.getString("MY_DATA")}")
        }

方法解析
.setInputData(workDataOf( “MY_DATA” to “这是我传的参数”))`:

这行代码设置了工作请求的输入数据。输入数据可以用来传递参数给 Worker 任务。这里,它设置了一个键为 "MY_DATA" 的数据,值为 "这是我传的参数"。这意味着在 MyWorkerdoWork() 方法中,可以通过 inputData 获取这个参数。

MyWorker更改为如下:

import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class MyWorker(appContext: Context, workerParams: WorkerParameters):Worker(appContext, workerParams) {
    companion object{
        private const val TAG = "MyWorker"
    }


    override fun doWork(): Result {


        val input =
            inputData.getString("MY_DATA") ?: return Result.failure()
        Log.d(TAG, "doWork: 我正在做一些工作 $input")
        return Result.success(inputData)
    }

}

这里的inputData就是setInputData中传过来的,然后在success中传递给getWorkInfoByIdLiveData的观察者。

执行结果如下:

2024-01-18 11:35:59.761 12706-12772 MyWorker                com.example.test                     D  doWork: 我正在做一些工作 这是我传的参数
2024-01-18 11:35:59.762 12706-12706 MainActivity            com.example.test                     D  testWorkManager: null
2024-01-18 11:35:59.762 12706-12706 om.example.tes          com.example.test                     I  SmartGc CheckAndAddTask : enable = 1 periodCheck = 1
2024-01-18 11:35:59.781 12706-12750 WM-WorkerWrapper        com.example.test                     I  Worker result SUCCESS for Work [ id=77bfbabb-4234-4db0-8c74-f6d7aeda1b72, tags={ com.example.test.MyWorker, myWorker } ]
2024-01-18 11:35:59.818 12706-12706 MainActivity            com.example.test                     D  testWorkManager: null
2024-01-18 11:35:59.830 12706-12706 MainActivity            com.example.test                     D  testWorkManager: 这是我传的参数

总结

本文主要介绍了WorkManager的一些基础使用,基础基本上学完了,后面学进阶一点的未完期待…

参考资料

WorkManager API
使用 WorkManager 调度任务
官方GitHub 代码示例
WorkManager 使用入门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1394030.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

权威认证!腾讯微搭入选Forrester《2023年第四季度中国专业开发人员低代码平台市场分析报告》

在Forrester近日发布的《The Low-Code Platforms For Professional Developers Landscape In China,Q4 2023》&#xff08;《2023年第四季度中国专业开发人员低代码平台市场分析报告》&#xff09;中&#xff0c;腾讯云成功入选。该报告通过对中国的低代码市场进行了深入的研究…

2018年认证杯SPSSPRO杯数学建模C题(第一阶段)机械零件加工过程中的位置识别全过程文档及程序

2018年认证杯SPSSPRO杯数学建模 基于轮廓特征的机械零件位置识别研究 C题 机械零件加工过程中的位置识别 原题再现&#xff1a; 在工业制造自动生产线中&#xff0c;在装夹、包装等工序中需要根据图像处理利用计算机自动智能识别零件位置&#xff0c;并由机械手将零件自动搬…

[Android] Android架构体系(1)

文章目录 Android 的框架Dalvik 虚拟机JNI原生二进制可执行文件Android NDK中的binutils Bionic谷歌考虑到的版权问题Bionic与传统的C标准库&#xff08;如glibc&#xff09;的一些不同 参考 Android 的框架 Android 取得成功的关键因素之一就是它丰富的框架集。 没有这些框架…

游卡:OceanBase在游戏核心业务的规模化降本实践

从 2023 年 9 月测试 OceanBase&#xff0c;到如今 3 个核心业务应用 OceanBase&#xff0c;国内最早卡牌游戏研发者之一的游卡仅用了两个月。是什么原因让游卡放弃游戏行业通用的 MySQL方案&#xff0c;选择升级至 OceanBase&#xff1f;杭州游卡网络技术有限公司&#xff08;…

WordPress设置回收站自动清理天数的插件Change Empty Trash Time

前面boke112百科跟大家分享的『WordPress回收站自动清空时间&#xff1f;如何关闭回收站或设置自动清理天数&#xff1f;』一文&#xff0c;就介绍了可以添加一行代码实现关闭或设置回收站自动清理时间&#xff0c;也可以通过安装Change Empty Trash Time插件来实现。 今天bok…

Jenkins-Pipeline

Pipeline 1 安装插件 2 新建一个 Pipline 工程 3 配置Pipeline 脚本 agent的使用可以参考这个文档 pipeline {agent anystages {stage(Build) { steps {echo Building project...}}stage(Test) { steps {echo Testing project...}}stage(Deploy) { steps {echo Deploying …

模具制造企业ERP系统有哪些?企业怎么选型适配的软件

模具的生产管理过程比较繁琐&#xff0c;涵盖接单报价、车间排期、班组负荷评估、库存盘点、材料采购、供应商选择、工艺流转、品质检验等诸多环节。 有些采用传统管理手段的模具制造企业存在各业务数据传递不畅、信息滞后、不能及时掌握订单和车间生产情况&#xff0c;难以对…

SD-WAN企业组网:实现高效、安全的跨国企业连接

在当今数字化时代&#xff0c;企业日益全球化&#xff0c;跨国办公成为常态。为了应对这一挑战&#xff0c;越来越多的企业选择采用先进的网络技术&#xff0c;其中SD-WAN&#xff08;软件定义广域网&#xff09;便是一种备受青睐的解决方案。 什么是SD-WAN企业组网&#xff1…

【LeetCode每日一题】2171. 拿出最少数目的魔法豆

2024-1-18 文章目录 [2171. 拿出最少数目的魔法豆](https://leetcode.cn/problems/removing-minimum-number-of-magic-beans/)思路&#xff1a; 2171. 拿出最少数目的魔法豆 思路&#xff1a; 对输入的数组进行排序&#xff0c;使得数组中的元素按照升序排列。初始化一个变量s…

易懂的方式讲解ARM中断原理以及中断嵌套方法

ARM有七种模式&#xff0c;我们这里只讨论SVC、IRQ和FIQ模式。 我们可以假设ARM核心有两根中断引脚&#xff08;实际上是看不见的&#xff09;&#xff0c;一根叫 irq pin, 一根叫fiq pin。在ARM的cpsr中&#xff0c;有一个I位和一个F位&#xff0c;分别用来禁止IRQ和FIQ。 先…

flink 最后一个窗口一直没有新数据,窗口不关闭问题

flink 最后一个窗口一直没有新数据&#xff0c;窗口不关闭问题 自定义实现 WatermarkStrategy接口 自定义实现 WatermarkStrategy接口 代码&#xff1a; public static class WatermarkDemoFunction implements WatermarkStrategy<JSONObject>{private Tuple2<Long,B…

第17章_反射机制拓展练习(关于Class,反射的应用,综合练习)

文章目录 第17章_反射机制拓展练习关于Class1、获取Class对象 反射的应用2、创建对象3、修改属性值4、调用方法5、获取类型信息6、榨汁机7、获取泛型参数8、自定义注解19、自定义注解2 综合练习10、AtguiguDemo11、AtguiguStudent12、自定义注解 第17章_反射机制拓展练习 关于C…

AttributeError: ‘DataFrame‘ object has no attribute ‘ix‘

文章目录 报错信息报错原因解决方案 报错信息 AttributeError: DataFrame object has no attribute ix 报错原因 这个ix属性在最新的pandas版本中已经升级修改。 解决方案 修改前 column01 dataset.ix[1, roomtype] 修改后 column01 dataset.loc[:,total_price] 关注公…

芯片制造上下游产业链及其工艺

整个产业链可分为&#xff1a;设计验证&#xff0c;晶圆制造&#xff0c;封装测试 设计验证&#xff1a;系统设计&#xff0c;逻辑设计&#xff0c;电路设计&#xff0c;物理设计 晶圆制造&#xff1a;拉单晶&#xff0c;磨外圆&#xff0c;切片&#xff0c;倒角&#xff0c;…

海思3559 yolov5模型转wk详细笔记

文章目录 前言1.编译caffer1.1安装虚拟机1.2安装caffer1.3编译python接口 2.适应wk的yolov5模型训练2.1下载yolov5-6.0项目源码2.2安装yolov5-6.0运行环境2.3修改模型2.4修改数据集2.5修改模型算子2.6 模型训练 3.模型转换&#xff1a;pt->onnx->caffe->wk3.1 pt->…

Docker安装Nginx并部署MySQL容器构建

一.MySQL容器的构建 1.创建MySQL根目录及配置文件夹&data文件夹 mkdir -p mysql/{conf,data} 2.上传配置文件 将配置文件上传到conf文件夹&#xff08;数据库配置文件已放到置顶资源中&#xff09; 3.命令构建MySQL容器 /soft/mysql/conf/my.cnf:/etc/my.cnf目录为我们…

如何安装配置VisualSVN服务并实现公网访问本地服务【内网穿透】

文章目录 前言1. VisualSVN安装与配置2. VisualSVN Server管理界面配置3. 安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4. 固定公网地址访问 前言 SVN 是 subversion 的缩写&#xff0c;是一个开放源代码的版本控制系统…

STM32入门教程-2023版【4-1】OLED调试工具

关注 点赞 不错过精彩内容 大家好&#xff0c;我是硬核王同学&#xff0c;最近在做免费的嵌入式知识分享&#xff0c;帮助对嵌入式感兴趣的同学学习嵌入式、做项目、找工作! 一、概述 在这一节先提前介绍一下&#xff0c;在以后的教程中我们会经常用到这个显示屏&#xff0…

javaScript设计模式-工厂

它的好处是消除对象间的耦合度&#xff0c;在派生子类时提供了更大的灵活性。但盲目的把普通的构造函数扔在一边&#xff0c;并不值得提倡。如果要采一不可能另外换用一个类&#xff0c;或都不需要在运行期间在一系列可互换的类中进行选择&#xff0c;就不应该使用。这样在后期…

中仕公考:国考进面后资格复审需要准备什么?

参加国考面试的考生在资格审核阶段需要准备以下材料&#xff1a; 1、本人身份证、学生证或工作证复印件。 2、公共科目笔试准考证复印件。 3、考试报名登记表。 4、本(专)科、研究生各阶段学历、学位证书(应届毕业生没有可以暂时不提供)。 5、报名资料上填写的各类证书材料…