在当今快节奏的生活中,移动设备已经成为我们日常工作和生活不可或缺的一部分。然而,随着应用程序的复杂性不断增加,开发人员面临着一个重要的挑战:如何在后台执行任务,而不会影响用户的体验和设备的性能?
在过去,开发人员通常使用传统的后台服务或定时任务来解决这个问题。然而,这些方法往往很复杂,需要大量的代码和资源,并且很难管理和调度任务。幸运的是,谷歌最近推出了一个新的解决方案:安卓WorkManager。
安卓WorkManager是一个灵活、强大的后台任务调度库,旨在帮助开发人员轻松管理和执行后台任务。它提供了一种简单的方式来调度任务,无论是一次性任务、定期任务还是延迟任务,都可以很容易地实现。同时,WorkManager还提供了一系列强大的功能,如任务链、约束条件和灵活的重试机制,以确保任务能够在最佳的时间和条件下执行。
在本文中,我们将深入探讨安卓WorkManager的原理和用法,并通过实际示例演示如何使用它来解决常见的后台任务问题。无论您是一名初学者还是一名有经验的开发人员,本文都将为您提供宝贵的知识和实用的技巧,帮助您更好地利用安卓WorkManager来优化您的应用程序。让我们一起开始这段关于安卓WorkManager的探索之旅吧!
好吧,不多BB,其实是因为安卓12以上想起后台服务必须要悬浮窗权限,想起还有个WorkManager这种东西,去官网学习然后总结一下。
我们先copy一下官方的解释 ,借鉴,借鉴,读书人的事怎么能叫抄
对于WorkManager,官方是这样描述的:
WorkManager 是适合用于持久性工作的推荐解决方案。如果工作始终要通过应用重启和系统重新启动来调度,便是持久性的工作。由于大多数后台处理操作都是通过持久性工作完成的,因此 WorkManager 是适用于后台处理操作的主要推荐 API。
用人话来简单描述解释一下就是说:应用后台操作,现在安卓官方推荐使用WorkManager了,官方还给了一张WorkManager与延时后台任务的关系图便于我们理解
我翻译了一下有些不太准,凑合着看吧
类型 | 周期 | 使用方式 |
---|---|---|
立即(马上执行) | 一次性 | OneTimeWorkRequest 和 Worker。如需处理加急工作,请对 OneTimeWorkRequest 调用 setExpedited()。 |
可延期(延期执行) | 一次性或定期 | PeriodicWorkRequest 和 Worker。 |
长期运行(满足条件执行) | 一次性或定期 | 任意 WorkRequest 或 Worker。在工作器中调用 setForeground() 来处理通知。 |
写下这篇文章时的最新依赖是 2023 年 2 月 8 日的 2.8.0 版本
将以下依赖项添加到应用的 build.gradle 文件中:
dependencies {
def work_version = "2.8.0"
// (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"
// optional - Multiprocess support
implementation "androidx.work:work-multiprocess:$work_version"
}
具体来说,上述配置包括以下依赖项:
androidx.work:work-runtime
:用于Java项目的基本依赖项。androidx.work:work-runtime-ktx
:用于Kotlin项目的基本依赖项,结合协程使用。androidx.work:work-rxjava2
:可选的依赖项,用于支持使用RxJava2编写任务。androidx.work:work-gcm
:可选的依赖项,用于支持使用GCMNetworkManager调度任务(API级别低于23的设备)。androidx.work:work-testing
:可选的依赖项,用于编写测试辅助工具。androidx.work:work-multiprocess
:可选的依赖项,用于支持任务在多进程中运行。在具体使用时,我们需要先定义工作,我们先创建一个MyWorker类,继承woker,注意不要导错包。
写好后应该是这个样子的
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()
}
}
在doWork()这个方法中,我们可以进行一系列操作,像是下载图片啊,更新安装包啊,都是可以的,方法需要一个Result 回参,我们看看Result 这个类
我们再借鉴一下官方的说法:
从 doWork() 返回的 Result 会通知 WorkManager 服务工作是否成功,以及工作失败时是否应重试工作。
所以示例中的return Result.success()就表示工作执行成功了
示例嘛,我们就在activity中调用WorkRequest了,在activity的onCreate()方法中调用如下代码:
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkRequest
//通过OneTimeWorkRequestBuilder创建WorkRequest
val mWorkerRequest : WorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
// .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
//通过WorkManager提交WorkRequest,执行MyWorker
WorkManager
.getInstance(this)
.enqueue(mWorkerRequest)
运行后可以在logcat中看到如下日志:
2023-12-19 11:13:46.675 31499-31570 MyWorker com.example.test D doWork: 我正在做一些工作
2023-12-19 11:13:46.684 31499-31541 WM-WorkerWrapper com.example.test I Worker result SUCCESS for Work [ id=9012bb3b-ccbb-4bbe-8e1c-1c84264410fb, tags={ com
对于这种简单的只需要执行一次的任务,推荐我们使用静态的方式创建
//通过静态方式创建的
val mWorkerRequest1 = OneTimeWorkRequest.from(MyWorker::class.java)
//通过WorkManager提交WorkRequest,执行MyWorker
WorkManager
.getInstance(this)
.enqueue(mWorkerRequest1)
同样会输出以下日志
2023-12-19 11:18:16.519 32612-32682 MyWorker com.example.test D doWork: 我正在做一些工作
2023-12-19 11:18:16.533 32612-32663 WM-WorkerWrapper com.example.test I Worker result SUCCESS for Work [ id=5cfd14e8-791f-4b31-968c-c5404963ebba, tags={ com.example.test.MyWorker } ]
缺点呢就是不能进行其他灵活的配置,比如加急,延时和添加约束。
下面介绍的setXXX方法都是WorkRequest的衍生方法,使用需要在.build()方法前
如果有多个任务,我们还可以使用setExpedited方法对任务进行加急,我们来看看源码
先看看setExpedited方法:
这个方法表示为任务请求加急的意思,需要一个OutOfQuotaPolicy入参,我们来看看OutOfQuotaPolicy类
从上面的源码来看我们只有一个任务时,设置.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)与不设置是等价的。而设置了加急的任务我们怎么知道是被加急了呢?在某些安卓设备上我们能收到通知,这与设备厂商和安卓版本有关。如果能收到的话我们创建Worker时使用CoroutineWorker,并集成其getForegroundInfo方法,然后,在 doWork() 内将其传递给 setForeground()。这样做会在 Android 12 之前的版本中创建通知。
您应该将 setForeground() 封装在 try/catch 块中,以捕获可能出现的 IllegalStateException。如果您的应用此时无法在前台运行,便可能会发生这类异常。在 Android 12 及更高版本中,您可以使用更详细的 ForegroundServiceStartNotAllowedException。
下面这段代码表示会延迟十分钟再执行。
val mWorkerRequest2 = OneTimeWorkRequestBuilder<MyWorker>()
.setInitialDelay(10, TimeUnit.MINUTES)
.build()
//通过WorkManager提交WorkRequest,执行MyWorker
WorkManager
.getInstance(this)
.enqueue(mWorkerRequest2)
执行工作器的确切时间还取决于 WorkRequest 中使用的约束和系统优化方式。WorkManager 经过设计,能够在满足这些约束的情况下提供可能的最佳行为。
上面的注意事项提到了约束,及一些特定的条件,android也帮我们归纳好了:
约束名称 | 约束作用 |
---|---|
NetworkType | 约束运行工作所需的网络类型。例如 Wi-Fi (UNMETERED)。 |
BatteryNotLow | 如果设置为 true,那么当设备处于“电量不足模式”时,工作不会运行。 |
RequiresCharging | 如果设置为 true,那么工作只能在设备充电时运行。 |
DeviceIdle | 如果设置为 true,则要求用户的设备必须处于空闲状态,才能运行工作。在运行批量操作时,此约束会非常有用;若是不用此约束,批量操作可能会降低用户设备上正在积极运行的其他应用的性能。 |
StorageNotLow | 如果设置为 true,那么当用户设备上的存储空间不足时,工作不会运行。 |
那么这些约束要怎么使用呢?
比如我们要在充电时做一些工作,就可以这样写
val constraints = Constraints.Builder()
.setRequiresCharging(true)
.build()
val mWorkerRequest3 = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(constraints)
.build()
//通过WorkManager提交WorkRequest,执行MyWorker
WorkManager
.getInstance(this)
.enqueue(mWorkerRequest3)
因为我是USB充电调试,日志输出为
2023-12-19 13:22:14.597 27819-27906 MyWorker com.example.test D doWork: 我正在做一些工作
2023-12-19 13:22:14.616 27819-27870 WM-WorkerWrapper com.example.test I Worker result SUCCESS for Work [ id=c3898a3d-13d1-4dc5-86e4-234f282dfcec, tags={ com.example.test.MyWorker } ]
本文主要介绍了WorkManager的一些基础使用,未完期待…
WorkManager API
使用 WorkManager 调度任务
官方GitHub 代码示例
WorkManager 使用入门