Android Jetpack库重要组件WorkManager的使用

目录
  • 前言
  • 后台处理指南
  • 后台处理面临的挑战
  • 如何选择合适的后台解决方案
  • WorkManager概述
  • WorkManager使用
    • 1 声明依赖项
    • 2 自定义一个继承自Worker的类
    • 3 选择worker执行的条件
    • 4 下面贴出自定义worker类的全部源码
    • 5 执行任务的方式
    • 6 取消任务的执行

前言

WorkManager是Jetpack很重要的一个组件; 本篇我们就先来讲讲它是如何使用的,在讲解之前我们先了解关于后台处理的一些痛点

后台处理指南

我们知道每个 Android 应用都有一个主线程,它负责处理界面(包括测量和绘制视图)、协调用户互动以及接收生命周期事件; 如果有太多工作在主线程中进行,则应用可能会挂起或运行速度变慢,从而导致用户体验不佳。任何长时间运行的计算和操作(例如解码位图、访问磁盘或执行网络请求)都应在单独的后台线程上完成

一般来说,任何所需时间超过几毫秒的任务都应该分派到后台线程; 在用户与应用积极互动时,可能需要执行几项这样的任务;即使在用户没有积极使用应用时,应用可能也需要运行一些任务(例如,定期与后端服务器同步或定期从应用内提取新内容)

后台处理面临的挑战

后台任务会使用设备的有限资源,例如 RAM 和电池电量; 如果处理不当,可能会导致用户体验不佳;为了最大限度地延长电池续航时间并强制推行良好的应用行为,Android 会在应用(或前台服务通知)对用户不可见时,限制后台工作;为此Google在不同平台上逐步的改进

Android 6.0(API 级别 23)引入了低电耗模式和应用待机模式

低电耗模式会在未插接设备的电源,在屏幕关闭的情况下,让设备在一段时间内保持不活动状态,那么设备就会进入低电耗模式; 在低电耗模式下,系统会尝试通过限制应用访问占用大量网络和 CPU 资源的服务来节省电量。它还会阻止应用访问网络,并延迟其作业、同步和标准闹钟

系统会定期退出低电耗模式一小段时间,让应用完成其延迟的活动; 在此维护期内,系统会运行所有待处理的同步、作业和闹钟,并允许应用访问网络。在每个维护期结束时,系统会再次进入低电耗模式,暂停网络访问并推迟作业、同步和闹钟

随着时间的推移,系统安排维护期的次数越来越少,这有助于在设备未连接至充电器的情况下长期处于不活动状态时降低耗电量; 一旦用户通过移动设备、打开屏幕或连接至充电器唤醒设备,系统就会立即退出低电耗模式,并且所有应用都会恢复正常活动

应用待机模式允许系统判定应用在用户未主动使用它时是否处于闲置状态; 当用户有一段时间未触摸应用时,系统便会作出此判定;当用户将设备插入电源时,系统会从待机状态释放应用,允许它们自由访问网络并执行任何待处理的作业和同步。如果设备长时间处于闲置状态,系统将允许闲置应用访问网络,频率大约每天一次

低电耗模式和应用待机模式管理在 Android 6.0 或更高版本上运行的所有应用的行为,无论它们是否专用于 API 级别 23

Android 7.0(API 级别 24)限制了隐式广播

引入了随时随地使用低电耗模式; 使得低电耗模式又前进了一步,随时随地可以省电;只要屏幕关闭了一段时间,且设备未插入电源,低电耗模式就会对应用使用熟悉的 CPU 和网络限制;这意味着用户即使将设备放入口袋里也可以省电

Android 8.0(API 级别 26)进一步限制后台行为

例如在后台获取位置信息和释放缓存的唤醒锁定

Android 9.0(API 级别 28)引入了应用待机存储分区

通过它,系统会根据应用使用模式动态确定应用资源请求的优先级; 应用待机存储分区有助于系统根据应用的使用时间新近度和使用频率对应用资源请求确定优先级

根据应用使用模式,每个应用都会被放置在五个优先级存储分区之一中; 系统会根据应用所在的存储分区限制每个应用可用的设备资源

  • Android 6.0(API 级别 23)引入了低电耗模式和应用待机模式

低电耗模式会在屏幕处于关闭状态且设备处于静止状态时限制应用行为; 应用待机模式会将未使用的应用置于一种特殊状态,进入这种状态后,应用的网络访问、作业和同步会受到限制

  • Android 7.0(API 级别 24)限制了隐式广播,并引入了随时随地使用低电耗模式
  • Android 8.0(API 级别 26)进一步限制了后台行为,例如在后台获取位置信息和释放缓存的唤醒锁定
  • Android 9(API 级别 28)引入了应用待机存储分区,通过它,系统会根据应用使用模式动态确定应用资源请求的优先级

如何选择合适的后台解决方案

下面有一张图完美的解答了这个问题

  • 从上图我们可以清晰的了解如何选择后台解决方案,如果是一个长时间的http下载的话就使用DownloadManager
  • 否则的话就看是不是一个可以延迟的任务,如果不可以就使用Foreground service
  • 如果是的话就看是不是可以由系统条件触发,如果是的话就使用WorkManager
  • 如果不是就看是不是需要在一个固定的时间执行这个任务,如果是的话就使用AlarmManager
  • 如果不是的话就使用WorkManager

WorkManager概述

  • 使用 WorkManager API 可以轻松地调度可延迟的工作以及预计即使您的设备或应用重启也会运行的工作,即使在应用退出或设备重启时仍应运行的可延迟异步任务
  • 最高向后兼容到 API 14
  • 在运行 API 23 及以上级别的设备上使用 JobScheduler
  • 在运行 API 14-22 的设备上结合使用 BroadcastReceiver 和 AlarmManager
  • 添加网络可用性或充电状态等工作约束
  • 调度一次性或周期性异步任务
  • 监控和管理计划任务
  • 将任务链接起来
  • 确保任务执行,即使应用或设备重启也同样执行任务
  • 遵循低电耗模式等省电功能

WorkManager使用

1 声明依赖项

dependencies {
  def work_version = "2.3.1"

// (Java only)
    implementation "androidx.work:work-runtime:$work_version"

// Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

// optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"

// optional - GCMNetworkManager support
    implementation "androidx.work:work-gcm:$work_version"

// optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"
}

2 自定义一个继承自Worker的类

重写doWork方法,或者使用协程的话,得继承自CoroutineWorker。doWork方法有一个返回值,来标记任务是否成功或者是否要retry; 返回值有三种,分别是Result.success(),Result.failure(),Result.retry()

执行成功返回Result.success() 执行失败返回Result.failure() 需要重新执行返回Result.retry()

override fun doWork(): Result {
    for (i in 1..3) {
        Thread.sleep(500)
        Log.i("aaa", "count: $i parameter: ${inputData.getString("parameter1")}")
    }
    return Result.success(Data.Builder().putString("result1", "value of result1").build())
}

3 选择worker执行的条件

//添加约束
val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .setRequiresBatteryNotLow(false)
                .setRequiresCharging(false)
                .setRequiresDeviceIdle(false)
                .setRequiresStorageNotLow(false)
                .build()
  //对一次性执行添加约束,如果返回faliure或者retry的话就在适当的约束条件下执行worker
  val request = OneTimeWorkRequestBuilder<CountWorker>()
                .setConstraints(constraints)
                .setInputData(Data.Builder().putString("parameter1", "value of parameter1").build())
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.HOURS)
                .build()
 WorkManager.getInstance(context).enqueue(request)
//或者定时每隔一个小时执行任务
val periodicWorkRequest = PeriodicWorkRequest.Builder(AppsWorker::class.java,
                                    1, TimeUnit.HOURS)
                                     .setConstraints(constraints)
                                     .build();
 WorkManager.getInstance(context).enqueue(periodicWorkRequest)

需要注意的是类似于JobSceeduler,周期性执行的任务最少间隔时间不能小于15mins

4 下面贴出自定义worker类的全部源码

class CountWorker(context: Context, parameters: WorkerParameters)
    : Worker(context, parameters) {
    companion object {
        fun enqueue(context: ComponentActivity) {
            val constraints = Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .setRequiresBatteryNotLow(false)
                    .setRequiresCharging(false)
                    .setRequiresDeviceIdle(false)
                    .setRequiresStorageNotLow(false)
                    .build()
            val request = OneTimeWorkRequestBuilder<CountWorker>()
            		//-----1-----添加约束
                    .setConstraints(constraints)
                    //-----2----- 传入执行worker需要的数据
                    .setInputData(Data.Builder().putString("parameter1", "value of parameter1").build())
                    //-----3-----设置避退策略
                    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.HOURS)
                    .build()
             //-----4-----将任务添加到队列中
            //WorkManager.getInstance(context).enqueue(request)
            //或者采用uniqueName执行
        	WorkManager.getInstance(context).beginUniqueWork("uniqueName", ExistingWorkPolicy.REPLACE, request).enqueue()
            //-----5-----对任务加入监听
            WorkManager.getInstance(context).getWorkInfoByIdLiveData(request.id).observe(context, Observer {
            	//-----8----获取doWork中传入的参数
                Log.i("aaa", "workInfo ${it.outputData.getString("result1")} ${it.state}: ")
            })
            //或者采用tag的方式监听状态
            WorkManager.getInstance(context).getWorkInfosByTagLiveData("tagCountWorker").observe(context, Observer {
            Log.i("aaa", "workInfo tag-- ${it[0].outputData.getString("result1")} ${it[0].state}: ")
        	})
        	//或者采用uniqueName的形式监听任务执行的状态
        	WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("uniqueName").observe(context, Observer {
            Log.i("aaa", "workInfo uniqueName-- ${it[0].outputData.getString("result1")} ${it[0].state}: ")
       	 })
        }
    }
    override fun doWork(): Result {
        for (i in 1..3) {
            Thread.sleep(500)
            //-----6-----获取传入的参数
            Log.i("aaa", "count: $i parameter: ${inputData.getString("parameter1")}")
        }
       //-----7-----传入返回的参数
        return Result.success(Data.Builder().putString("result1", "value of result1").build())
    }
}
  • 为了测试方便,我把执行的代码写在了enqueue中了,在enqueue中,我们首先在注释1处添加了约束
  • 在注释2处添加了执行worker需要的参数。这个参数可以在doWork中获取到,如注释6处所示;传入的数据不能超过10kb
  • 注释3处我们设置了避退策略,如果我们的一次性任务返回了retry,这里就可以起作用了,避退策略有两种方式。一种是指数级的EXPONENTIAL,还有一种是线性的LINEAR
  • 然后注释4处将任务加入到队列中,这里仅仅是加入队列,并不能保证执行,因为WorkManager主要的定位就是针对可延迟的任务,它需要根据添加的约束和系统自身的情况来做出什么时间执行这个任务
  • 注释5处可以根据request的id获取到任务的执行状态,返回值是一个LiveData类型的,并将其加入到生命周期观察序列中;所以当任务的执行状态发生变化的时候就会在注释8处打印信息
  • 我们还可以在任务执行结束的时候传入需要返回的参数,但是只能在success和failure的时候传入,传入的数据可以再注释8处获取

5 执行任务的方式

如果我们想要以链式执行一系列任务,如图所示,我们可以使用:

 WorkManager.getInstance(context).beginWith(requestA).then(requestB).enqueue()

如果我们的任务A和任务B之间没有关系,需要在任务A和B都完成的情况下执行任务C的话,如图所示,这时候就可以这么调用:

WorkManager.getInstance(context).beginWith(listOf(requestA,requestB)).then(requestC).enqueue()

如果我们想要AB和CD并行的执行完,然后执行E的话,如图所示,可以采用:

val continuation1 = WorkManager.getInstance(context).beginWith(requestA).then(requestB)
val continuation2 = WorkManager.getInstance(context).beginWith(requestC).then(requestD)
WorkContinuation.combine(listOf(continuation1, continuation2)).then(requestE).enqueue()

需要注意的是任务一旦发起,任务是可以保证一定会被执行的,就算退出应用,甚至重启手机都阻止不了他;但可能由于添加了环境约束等原因会在不确定的时间执行罢了

6 取消任务的执行

//通过request.id取消任务
WorkManager.getInstance(context).cancelWorkById(request.id)
//通过request的tag取消任务
WorkManager.getInstance(context).cancelAllWorkByTag("tag")
//通过request的uniqueName取消任务
WorkManager.getInstance(context).cancelUniqueWork("uniqueName")
//取消所有的work任务
WorkManager.getInstance(context).cancelAllWork()

以上可以看到可以通过四种方式取消任务

到此这篇关于Android Jetpack库重要组件WorkManager的使用的文章就介绍到这了,更多相关Android Jetpack WorkManager内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android WorkManager浅谈

    一.原文翻译 WorkManager API 可以很容易的指定可延迟的异步任务.允许你创建任务,并把它交给WorkManager来立即运行或在适当的时间运行.WorkManager根据设备API的级别和应用程序状态等因素来选择适当的方式运行任务.如果WorkManager在应用程序运行时执行你的任务,它会在应用程序进程的新线程中执行.如果应用程序没有运行,WorkManager会根据设备API级别和包含的依赖项选择适当的方式安排后台任务,可能会使用JobScheduler.Firebase Jo

  • Android使用Kotlin API实践WorkManager

    WorkManager 提供了一系列 API 可以更加便捷地规划异步任务,即使在应用被关闭之后或者设备重启之后,仍然需要保证立即执行的或者推迟执行的任务被正常处理.对于 Kotlin 开发者,WorkManager 为协程提供了最佳的支持.在本文中,我将通过实践 WorkManager codelab 为大家展示 WorkManager 中与协程相关的基本操作.那么让我们开始吧! WorkManager 基础 当您需要某个任务保持运行状态,即使用户切换到别的界面或者用户将应用切换到后台,甚至设备

  • Android开发Jetpack组件WorkManager用例详解

    目录 一.简介 二.导入 三.基本使用 3.1 定义后台任务 3.2 配置任务运行条件 3.2.1 只需执行一次的任务 3.2.2 周期性执行的任务 3.3 将任务传给 WorkManager 四.高级配置 4.1 设置任务延迟执行 4.2 给任务添加标签 4.3 取消任务 4.3.1 根据标签取消任务 4.3.2 根据 request 的 id 取消任务 4.3.3 取消所有任务 4.4 任务重试 4.5 监听任务结果 4.6 传递数据 4.7 链式任务 一.简介 WorkManager 用于

  • Android Jetpack库重要组件WorkManager的使用

    目录 前言 后台处理指南 后台处理面临的挑战 如何选择合适的后台解决方案 WorkManager概述 WorkManager使用 1 声明依赖项 2 自定义一个继承自Worker的类 3 选择worker执行的条件 4 下面贴出自定义worker类的全部源码 5 执行任务的方式 6 取消任务的执行 前言 WorkManager是Jetpack很重要的一个组件: 本篇我们就先来讲讲它是如何使用的,在讲解之前我们先了解关于后台处理的一些痛点 后台处理指南 我们知道每个 Android 应用都有一个主

  • Android Jetpack库剖析之ViewModel组件篇

    前言 今天让我们一起去探究一下ViewModel的实现原理,描述的不对或不足还请海涵,仅作为参考 ViewModel简介 ViewModel是一个可感知Activity或Fragment生命周期的一个架构组件,当视图销毁,数据也会被清除,所以它的本质就是用来存储与视图相关的数据,让视图显示控制与数据分离,即使界面配置发生改变数据也不会被销毁,通常配合LiveData使用 ViewModel用法 class MainActivity : AppCompatActivity() { override

  • Android Jetpack库剖析之LiveData组件篇

    目录 LiveData简介 LiveData用法 数据订阅过程 PostValue过程 SetValue过程 生命周期变化 LiveData简介 在日常安卓开发中,一些耗时的操比如列网络请求,数据库读写都不能在主线程执行,必须开一条子线程去执行这些耗时操作,但我们往往需要在这些耗时操作执行完毕后更新UI,但安卓不能在子线程进行UI的更新,这时我们只能通过创建一个Handler来切回到主线程进行UI的更新,直到LiveData出现,LiveData是一个可被观察的数据容器,它将数据包装起来,使数据

  • Android Jetpack库剖析之Lifecycle组件篇

    目录 提纲 什么是Lifecycle 如何使用Lifecycle 关系梳理 Activity是如何实现Lifecycle的 CompatActivity AppCompatActivity Fragment是如何实现Lifecycle的 Lifecycle是如何下发宿主生命周期给观察者的 提纲 1,什么是Lifecycle? 2,如何使用Lifecycle? 3,LifecycleOwner,Lifecycle,LifecycleObserver之间是什么关系? 3,Activity是如何实现L

  • Android Jetpack导航组件Navigation创建使用详解

    目录 引言 依赖项 创建导航图 导航宿主 导航到目的地 传递参数 NavigationUI 多模块导航 引言 导航是指支持用户导航.进入和退出应用中不同内容片段的交互.Android Jetpack 的导航组件可实现导航,无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对. 依赖项 def nav_version = "2.5.2" implementation "androidx.navigation:navigation-fragment-kt

  • Android Jetpack组件中LifeCycle作用详细介绍

    目录 Jetpack 1.那么Jetpack是什么呢 2.为何使用Jetpack 3.Jetpack与AndroidX LifeCycle 1.LifeCycle的作用 2.LifeCycle应用 1.设计组件 2.使用组件 3.总结LifeCycle的使用 Jetpack Jetpack,我觉得翻译为“飞行器”更好听,因为Google针对编程历史乱象,整理出一套组件库,帮助开发者创造更完美的应用作品.现在市面上,很多公司招聘面试要求渐渐把Jetpack看作必会技能,Google也在疯狂的安利J

  • Android JetPack组件的支持库Databinding详解

    目录 简介 启用databinding 布局xml variable (变量标签) data (数据标签) @{}表达式 绑定普通数据 绑定可观察数据 对单个变量的绑定-fields 对集合的绑定-collections 绑定对象-objects 绑定LiveData 双向绑定 简介 DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源.使其维护起来更加方便,架构更明确简介. DataBinding 唯一

  • Android Jetpack组件支持库DataBinding与ViewModel与LiveData及Room详解

    目录 一.官方推荐的Jetpack架构 二.添加依赖 三.创建Repository 四.创建ViewModel 五.activity中使用 Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle 一.官方推荐的Jetpack架构 ViewModel是介于View(视图)和Model(数据模型)之间的中间层,能够使视图和数据分离,又能提供视图和数据之间的通信. LiveData是一个能够在ViewModel中数据发生变化时通知页面刷

  • Android Jetpack组件库LiveData源码深入探究

    目录 前言 一.LiveData 二.使用案例 三.LiveData 实现原理 四.LiveData 相关源码 五.LiveData分发问题 Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle Android Jetpack之DataBinding+ViewModel+LiveData+Room 前言 Jetpack是一个由多个技术库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种Android版本和设备中一致

随机推荐