Android 架构组件之 WorkManager

2024-02-25 16:58

本文主要是介绍Android 架构组件之 WorkManager,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1. 什么是后台任务?
    • 2. 为什么要使用 WorkManager?
    • 3. 通过一个简单的案例,介绍如何使用 WorkManager
    • 4. 分析 WorkManager 的组成及原理
      • 4.1 WorkManager 的组成
      • 4.2 WorkManager 的原理。
    • 5. WorkManager 的高级用法
      • 5.1 创建任务链
      • 5.2 观察后台任务的状态
    • 6. 总结
    • 参考链接

WorkManager是一个兼容性强、灵活和简单的延迟后台任务框架。本文将从以下几个方面对 WorkManager 进行介绍:

  • 先明确什么是 Android 中的后台任务?
  • 为什么要使用 WorkManager?
  • 通过一个简单的案例,介绍如何使用 WorkManager。
  • 分析 WorkManager 的组成及原理。
  • 最后对 WorkManager 的使用进行总结。

在分析 WorkManager 之前,先要明确后台任务是什么?

1. 什么是后台任务?

要了解后台任务,先来看看 Android 是如何定义前台应用的。前台任务通常有以下几个特点:

  • 具有一个处于前台的 Activity,Activity 的生命周期在resumed、 started 或 paused 状态;
  • 具有一个前台的服务,即 ForegroundService;
  • 一个前台的应用关联到该应用,这种关联方式可以是使用了该应用的ContentProvider,或者绑定了该应用的输入法服务 IME、壁纸服务 WallpaperService、NotificationListenerService、语音服务VoiceInteractionService、文本服务 Textservice 中的一个或者几个。

如果上面提到的这些都不满足,那么应用处于后台。

在后台运行应用会消耗有限的设备资源,比如内存和电池的电量,进而会影响用户体验。后台任务会缩短设备的续航时间,或者会造成设备的卡顿等。

于是 Google 在 Android 版本的演进过程中,对后台应用进行了各种限制,比如:

  • 低耗电模式和应用待机模式,如果设备未插接电源,处于空闲状态一段时间且屏幕关闭,系统会进入低耗电或者待机模式,并对应用行为施加相应限制;

  • 后台位置限制,对后台应用获取用户当前位置的频率进行限制;

  • 后台服务限制,限制应用在后台运行服务,并禁止应用通过隐式调用 CPU 或网络资源等。

2. 为什么要使用 WorkManager?

我们的应用不可能总处于前台,但是我们需要下载更新,需要与服务器进行同步,这些业务逻辑该怎么实现呢?Google 给我们提供了诸如 AsyncTask、AlarmManager、JobScheduler、SyncAdapter、Loader、Service、FirebaseJobDispatcher、GCM NetworkManager 等一系列框架。其中我们比较常用的有 AlarmManager、Service和 JobScheduler。

在 AlarmManager 文档中有这样一段提示:

Note: Beginning with API 19 (Build.VERSION_CODES.KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent).

可以看到在 API 19以后,使用 AlarmManager 不会像以前那样精确了。

再来看看 Service:

A Service is an application component that can perform long-running operations in the background, and it does not provide a user interface.

不恰当的使用 Service 和 AlarmManager,除了会对设备的续航时间有影响外,从 Android Oreo (API 26) 开始,如果一个应用的 targeting SDK 为 Android 8.0,那么当它在某些不被允许创建后台服务的场景下,调用 Service 的startService() 方法,会抛出IllegalStateException。

再来看看 JobScheduler:

JobScheduler 首先会调度一个任务,然后在合适的时机(比如说延迟若干时间之后,或者等手机空闲了)系统会开启你的MyJobService,然后执行 onStartJob() 里的处理逻辑。

ComponentName service = new ComponentName(this, MyJobService.class);
JobScheduler mJobScheduler = (JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(jobId, serviceComponent).setRequiredNetworkType(jobInfoNetworkType).setRequiresCharging(false).setRequiresDeviceIdle(false).setExtras(extras).build();
mJobScheduler.schedule(jobInfo);

但是 JobScheduler 只能在 API 23 及其以上才能使用,在 API 23 以下可以用 JobDispatcher。而 JobDispatcher 是 FireBase 中的类,需要 Google Play Services 的支持。

综上,WorkManager 应运而生。

WorkManager 为后台任务提供了一套统一的解决方案,它可以根据 Android 电量优化以及设备的 API 等级,选择合适的方式执行。WorkManager 向后兼容到 API 14,并且对无论集成 Google Play Service 服务与否的设备都予以支持。使用 WorkManager 管理任务,允许任务延迟,并且保证任务能够执行到,即使应用关闭或设备重启。

WorkManager 不适用于需要在特定时间触发的任务,也不适用立即任务。针对特定时间触发的任务使用 AlarmManager,立即执行的任务使用 ForegroundService。

3. 通过一个简单的案例,介绍如何使用 WorkManager

如果我们要完成一个图片上传的任务,大致如下:

总结一下,包括以下内容:

  • 在电量充足的情况下完成图片的过滤;
  • 在存储空间允许的情况下完成图片的压缩;
  • 最后在网络条件允许的条件下,完成图片的上传。

为此我们需要完成以下几个步骤:

**1. 首先在 Worker 中定义任务,即继承 Worker 类,实现 doWork()方法,确定输入输出的数据。**在这个案例中,输入和输出的数据都为图片的 uri,可以通过 Data 进行封装,值得注意的是,Data 对数据是有大小限制的,由参数 MAX_DATA_BYTES 限制,默认为 10KB。

class UploadWorker(appContext: Context, workerParams: WorkerParameters): Worker(appContext, workerParams) {override fun doWork(): Result {try {// Get the inputval imageUriInput = inputData.getString(Constants.KEY_IMAGE_URI)// Do the workval response = upload(imageUriInput)// Create the output of the workval imageResponse = response.body()val imgLink = imageResponse.data.link// workDataOf (part of KTX) converts a list of pairs to a [Data] object.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. 然后使用 WorkRequest 创建请求。**WorkRequest 类的主要作用是配置任务的运行方式和时间。在创建 WorkRequest 对象时可以添加限制条件,指定输入,并且选择单次或者周期性的方式来执行任务。这里添加限制条件为在网络连接时。这里选择了单次任务 OneTimeWorkRequest,如果是周期性的任务可以选择 PeriodicWorkRequest。

// Create the Constraints
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()// Define the input
val imageData = workDataOf(Constants.KEY_IMAGE_URI to imageUriString)// Bring it all together by creating the WorkRequest; this also sets the back off criteria
val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>().setInputData(imageData).setConstraints(constraints)        .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS).build()

setBackoffCriteria()方法可以设置在任务失败时的重试策略,可以设置重新调度需要等待的时间,配合着策略(框架给出了线性和指数两种方式 backoffPolicy)使用,默认开始30s,逐渐增加最多5小时。

3. 使用 WorkManager 的 enqueue()方法,将任务添加到队列中,

WorkManager.getInstance(context).enqueue(uploadWorkRequest)

至此完成了 WorkManager 上传图片的简单示例,即使应用退出或者设备重启,只要在满足网络的条件下,系统会在将来某个时刻完成上传图片的任务。

4. 分析 WorkManager 的组成及原理

先来看看 WorkManager 由哪些类组成。

4.1 WorkManager 的组成

按照惯例,先给出 WorkManager 相关的一张类图(基于work-runtime-ktx:2.2.0),在类图中根据职责的不同,进行了不同颜色的标注,绿色的 WorkManager 负责后台任务的调度;粉色的 Worker 及 WorkRequest 指代具体的后台任务,黄色的 Constrains 等主要是与后台任务,或者任务调度的参数配置及状态信息相关。下面逐一介绍:

针对类图中的内容,总结如下:
  • Worker 类是一个抽象类,我们需要继承 Worker 类,并实现 doWork()方法,在 doWork()方法中实现我们需要在后台执行的业务逻辑,我们可以将业务封装在多个 Woker 的实现类中。

  • WorkRequest 代表一个单独的后台任务。WorkRequest 类也是一个抽象类,我们通常会直接使用它的两个子类,OneTimeWorkRequest 和 PeriodicWorkRequest。

  • WorkRequest 还有一个内部类 WorkRequest.Builder,OneTimeWorkRequest.Builder 和 PeriodicWorkRequest.Builder都是 WorkRequest.Builder 的子类,Builder 使用的是创建者模式,我们通过 Builder 实例来创建具体的 WorkRequest 对象。

  • WorkRequest 可以指定那个 Worker 来执行任务。每一个 WorkRequest 实例都会生成唯一的id,可以通过 id 取消任务,或者获取任务的状态信息等。

  • Constraints 类用来设定执行任务的条件,比如设备空闲时、充电时、电量充足时等等,通过 WorkRequest 的 setConstraints() 方法将 Constraints 对象传入。

  • WorkInfo 用来记录任务信息,WorkInfo 有一个内部枚举State,用来保存任务的状态,一个后台任务有以下六种状态、分别是 ENQUEUED、RUNNING、SUCCEEDED、FAILED、BLOCKED 及 CANCELLED。

  • WorkInfo 除了记录任务的状态信息,还记录着任务的 id,tag 等,如果后台任务有输出的数据,也通过 WorkInfo 的成员变量 Data 对象得到。

  • 如果后台任务需要接收一些输入的参数数据,可以通过 Data 对象,Data.Builder 针对不同数据类型封装了一系列 putXXX()方法。后台任务执行后返回的结果,通过 Data 对象封装的一系列 getXXX()方法获取。

  • WorkContinuation,很多 WorkManager 的高级用法都与这个类有关,比如建立任务链等,后面在 WorkManager 的高级用法中详细介绍。

  • WorkManager,后台任务的调度器,它负责将我们创建好的 WorkRequest 对象添加到队列中,根据我们设定的约束条件(Constraints对象),并且会综合考虑设备资源的使用情况,进行任务的调度。

4.2 WorkManager 的原理。

前面提到 WorkManager 保证任务能够执行到,即使应用关闭或设备重启。再补充一点,WorkManager 保证后台任务运行在**主线程之外的线程。**我们分析一下 WorkManager 是如何做到的。

先给出一张原理图:

我们逐一分析一下:

  • Internal TaskExecutor, 一个单线程的线程池,用来处理后台任务的入队,并将 WorkRequest 信息保存到数据库中。当 WorkRequest 的触发条件满足时,从数据库中取出,并告诉 WorkFactory 创建 Worker 实例。

  • WorkManager database,WorkManager 会将后台任务保存到本地的数据库中,这也说明了为什么应用退出,设备重启,WorkManager 都能保证后台任务会被执行。在数据库中会存储后台任务的状态信息,输入输出数据,运行时的触发条件等等。

  • WorkerFactory,用来创建具体的 Worker 实例。

  • Default Executor,WorkManager 默认将后台任务运行在 Default Executor 线程池中,Default Executor 会调用 Worker 实例的 doWork() 方法,这也说明了 WorkManager 默认的后台任务运行在非主线程。

我们再来看一下 WorkRequest 有哪些状态信息:

通常 WorkRequest 有以上 6 中状态信息,它们之间的转换关系:

  • ENQUEUED,当 WorkRequest 被添加到队列,并且处在任务链的下一个任务,等待触发条件被满足。

  • RUNNING,在这种状态时,任务正在被执行,即 Worker 中的 doWork() 方法正在执行。在这种状态时,可以通过调用 Result.retry()方法,任务会继续回到 ENQUEUED 状态。

  • SUCCEEDED,在这种状态时,任务已经执行完,对于周期性的任务,没有这一状态,而是直接进入 ENQUEUED 状态,等待触发条件满足,再次执行。

  • FAILED,在这种状态时,任务在失败的状态下,已经执行完,任务不会再被执行。

  • BLOCKED,WorkRequest 的触发条件不满足,并且也不是任务链中下一个要执行的任务。

  • CANCELLED,当任务被取消时,会处在该状态,被取消的任务不会被执行,任务处在 ENQUEUED、RUNNING、BLOCKED 时都可以被取消,进入 CANCELLED 状态。

5. WorkManager 的高级用法

分析完 WorkManager 的原理,再来看一下 WorkManager 的一些高级用法。

5.1 创建任务链

在介绍 WorkManager 类图时,提到了 WorkContinuation 类,这个类主要用来将后台任务组装成任务链。需要指出的是,任务链只适合一次性任务 OneTimeWorkRequest,对于周期性任务 PeriodicWorkRequest 不适用;任务链中的某个任务的状态是 FAILURE,则整条任务链结束。

对于上面提到的上传图片的案例,如果现在要同时选择三张图片,进行压缩,上传。通过任务链的方式,可以用以下的方式:

WorkManager.getInstance().beginWith(Arrays.asList(filterImageOneWorkRequest, filterImageTwoWorkRequest, filterImageThreeWorkRequest)).then(compressWorkRequest).then(uploadWorkRequest).enqueue()

此外 WorkManager 允许用户可以创建任意的,非循环的任务依赖图,比如:

上面的任务链可以写成:

WorkContinuation left = workManager.beginWith(A).then(B);
WorkContinuation right = workManager.beginWith(C).then(D);
WorkContinuation final = WorkContinuation.combine(Arrays.asList(left, right)).then(E);
final.enqueue();

5.2 观察后台任务的状态

我们可以通过 WorkManager 中 getWorkInfoByXXX() 中的一系列方法,获取封装了 WorkInfo 的 LiveData 实例。WorkInfo 中封装了输出数据,及任务的状态信息。

比如上面的实例,如果图片上传成功后,将图片显示在 UI 上,可以进行如下操作,关于 LiveData 的分析可以参考之前的文章 Android 架构组件之 LiveData

// In your UI (activity, fragment, etc)
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))}})

6. 总结

WorkManager 作为 Android 推荐的后台管理工具,WorkManager 考虑了系统所有的后台限制,WorkManager 的任务可以单次执行、循环执行、组合执行,构成任务链,还可以对任务添加约束条件,比如设备空闲时,充电时,连接网络时等。

既然 WorkManager 这么强大,是不是所有的后台任务都可以使用 WorkManager 呢?答案是否定的。在选择后台管理工具之前,需要对应用的需求和场景的限制有清晰的认识。

如图中描述,WorkManager 不适用于需要在特定时间触发的任务,也不适用立即任务。

如果应用需要立刻执行一个由用户发起的任务,即使用户退出应用或关闭屏幕也不会影响任务的执行,使用前台服务。

如果需要在某一特定时间运行一个无法被推迟的任务,且该任务会触发操作并涉及用户交互,用 AlarmManager 中的 setExactAndAllowWhileIdle() 方法。常见的定时任务包括:服药提醒,电视节目开始前,向用户发送的提醒通知等。总结为下表。

用例示例选择方案
任务可推迟,必须要执行1.上传日志信息;2.对上传/下载的数据进行加密解密。3.同步数据WorkManager
用户发起的任务,需要立即执行,且应用退出后,任务依旧可以执行1.音乐播放器;2.路线导航等ForegroundService
特定时间,涉及与用户交互1.闹钟;2.服药提醒;3.节目开始前的提醒通知等AlarmManager

至此,WorkManager 就分析完了。

更多内容,可以订阅 我的博客


参考链接

(译)从Service到WorkManager
WorkManager Basics
Create an input method
android.service.textservice

这篇关于Android 架构组件之 WorkManager的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/746110

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

mybatis的整体架构

mybatis的整体架构分为三层: 1.基础支持层 该层包括:数据源模块、事务管理模块、缓存模块、Binding模块、反射模块、类型转换模块、日志模块、资源加载模块、解析器模块 2.核心处理层 该层包括:配置解析、参数映射、SQL解析、SQL执行、结果集映射、插件 3.接口层 该层包括:SqlSession 基础支持层 该层保护mybatis的基础模块,它们为核心处理层提供了良好的支撑。

百度/小米/滴滴/京东,中台架构比较

小米中台建设实践 01 小米的三大中台建设:业务+数据+技术 业务中台--从业务说起 在中台建设中,需要规范化的服务接口、一致整合化的数据、容器化的技术组件以及弹性的基础设施。并结合业务情况,判定是否真的需要中台。 小米参考了业界优秀的案例包括移动中台、数据中台、业务中台、技术中台等,再结合其业务发展历程及业务现状,整理了中台架构的核心方法论,一是企业如何共享服务,二是如何为业务提供便利。

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

系统架构设计师: 信息安全技术

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师: 信息安全技术前言信息安全的基本要素:信息安全的范围:安全措施的目标:访问控制技术要素:访问控制包括:等保

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk