Android Jetpack组件之WorkManager后台任务管理的介绍与使用(一)

一、介绍

Jetpack?

        我们经常看到,似乎很高端,其实这个就是一个名词,或者说是一种框架概念。

Jetpack 包含一系列 Android 库,它们都采用最佳做法并在 Android 应用中提供向后兼容性。

Jetpack 应用架构指南概述了构建 Android 应用时要考虑的最佳做法和推荐架构。

最终就是Android平台的一个介绍,有些新人看到又以为是什么平台,甚至一些招聘会写需要了解Room数据,Jetpack组件,其实我们现在好多已在使用了,但是非专业人会不停提jetpack导致一些人在理解的时候被吓到了。

JetPack组件已全部支出androidX,如果你的项目没有升级到AndroidX,请先升级到AdnroidX。

利用 Jetpack

Jetpack 库可以单独使用,也可以组合使用,以满足应用的不同需求。

  • WorkManager - 满足您的后台调度需求。
  • Room - 实现数据存储持久性。
  • Navigation - 管理应用导航流程。
  • CameraX - 满足相机应用需求。
  • 请参阅所有 Jetpack 库的概览

二、WorkManager

        WorkManager 是适合用于持久性工作的推荐解决方案。如果工作始终要通过应用重启和系统重新启动来调度,便是持久性的工作。由于大多数后台处理操作都是通过持久性工作完成的,因此 WorkManager 是适用于后台处理操作的主要推荐 API。

持久性工作的类型

WorkManager 可处理三种类型的持久性工作:

  • 立即执行:必须立即开始且很快就完成的任务,可以加急。
  • 长时间运行:运行时间可能较长(有可能超过 10 分钟)的任务。
  • 可延期执行:延期开始并且可以定期运行的预定任务。
持久性工作的类型
类型 周期 使用方式
立即 一次性 OneTimeWorkRequest 和 Worker

如需处理加急工作,请对 OneTimeWorkRequest 调用 setExpedited()

长期运行 一次性或定期 任意 WorkRequest 或 Worker。在工作器中调用 setForeground() 来处理通知。
可延期 一次性或定期 PeriodicWorkRequest 和 Worker

使用 WorkManager 保证工作可靠性

WorkManager 适用于需要可靠运行的工作,即使用户导航离开屏幕、退出应用或重启设备也不影响工作的执行。例如:

  • 向后端服务发送日志或分析数据。
  • 定期将应用数据与服务器同步。

WorkManager 不适用于那些可在应用进程结束时安全终止的进程内后台工作。它也并非对所有需要立即执行的工作都适用的通用解决方

三、接入

1、依赖库

//work
def  work_version = "2.7.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 - Multiprocess support
implementation "androidx.work:work-multiprocess:$work_version"

由于国内应用,GCM可以不需要,因为这个GCM是google service,国内的手机不支持

2、接入

2.1 先定义一个worker

工作使用 Worker 类定义。doWork() 方法在 WorkManager 提供的后台线程上异步运行

class MyWorks(context: Context,workerParameters: WorkerParameters) : Worker(context, workerParameters) {
    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {

        //后台异步执行

        var success=Result.Success()
        var error=Result.failure()
        var retry=Result.retry()

        return success
    }
}

doWokr():是我们需要执行的方法体,需要异步执行,都将在这边执行。最后将执行的结果返回即可Result。

从 doWork() 返回的 Result 会通知 WorkManager 服务工作是否成功,以及工作失败时是否应重试工作。

  • Result.success():工作成功完成。
  • Result.failure():工作失败。
  • Result.retry():工作失败,应根据其重试在其他时间尝试。
public Success(@NonNull Data outputData) {
    super();
    mOutputData = outputData;
}

创建 WorkRequest

        定义工作后,必须使用 WorkManager 服务进行调度该工作才能运行。对于如何调度工作,WorkManager 提供了很大的灵活性。您可以将其安排为在某段时间内定期运行,也可以将其安排为仅运行一次。

        不论您选择以何种方式调度工作,请始终使用 WorkRequest。Worker 定义工作单元,WorkRequest(及其子类)则定义工作运行方式和时间。在最简单的情况下,您可以使用 OneTimeWorkRequest

提交work执行:

val workRequest:WorkRequest=OneTimeWorkRequestBuilder<MyWorks>().build()
WorkManager.getInstance(application).enqueue(workRequest)

这种是一次性调度。

也可以通过from来创建request:

val workRequest=  OneTimeWorkRequest.from(MyWorks::class.java)

这种构建也只能构建简单的

复杂构建:

复杂的构建需要通过OneTimeWorkRequestBuilder来构建

val build=OneTimeWorkRequestBuilder<MyWorks>()
通过build来设置加载机制和延迟等

调度加急

        WorkManager 2.7.0 引入了加急工作的概念。这使 WorkManager 能够执行重要工作,同时使系统能够更好地控制对资源的访问权限。

加急工作具有以下特征:

  • 重要性:加急工作适用于对用户很重要或由用户启动的任务。
  • 速度:加急工作最适合那些立即启动并在几分钟内完成的简短任务。
  • 配额:限制前台执行时间的系统级配额决定了加急作业是否可以启动。
  • 电源管理电源管理限制(如省电模式和低电耗模式)不太可能影响加急工作。
  • 延迟时间:系统立即执行加急工作,前提是系统的当前工作负载允许执行此操作。这意味着这些工作对延迟时间较为敏感,不能安排到以后执行。

执行加急

从 WorkManager 2.7 开始,您的应用可以调用 setExpedited() 来声明 WorkRequest 应该使用加急作业,以尽可能快的速度运行。以下代码段展示了关于如何使用 setExpedited() 的示例

val request = OneTimeWorkRequestBuilder()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

向后兼容性和前台服务

为了保持加急作业的向后兼容性,WorkManager 可能会在 Android 12 之前版本的平台上运行前台服务。前台服务可以向用户显示通知。

在 Android 12 之前,工作器中的 getForegroundInfoAsync() 和 getForegroundInfo() 方法可让 WorkManager 在您调用 setExpedited() 时显示通知。

如果您想要请求任务作为加急作业运行,则所有的 ListenableWorker 都必须实现 getForegroundInfo 方法

override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
    
    return super.getForegroundInfoAsync()
}

CoroutineWorker:

        如果您使用 CoroutineWorker,则必须实现 getForegroundInfo()。然后,在 doWork() 内将其传递给 setForeground()。这样做会在 Android 12 之前的版本中创建通知

    override suspend fun getForegroundInfo(): ForegroundInfo {

        val id = Random.nextInt(0, Int.MAX_VALUE)
        return ForegroundInfo(id, getNotion())
        

    }


    private fun getNotion(): Notification {
        val notification = Notification()
        return notification;
    }

配额政策:

  • OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST:
           这会导致作业作为普通工作请求运行。上述代码段演示了此操作。
     
  • OutOfQuotaPolicy.DROP_WORK_REQUEST
    这会在配额不足时导致请求取消。

定期调度

您的应用有时可能需要定期运行某些工作,使用 PeriodicWorkRequest 创建定期执行的 WorkRequest

val request=PeriodicWorkRequestBuilder<MyWorks>(5,TimeUnit.MILLISECONDS)

解释:

        时间间隔定义为两次重复执行之间的最短时间。工作器的确切执行时间取决于您在 WorkRequest 对象中设置的约束以及系统执行的优化。

val reques1=PeriodicWorkRequestBuilder<MyWorks>(5,TimeUnit.HOURS,15,TimeUnit.MINUTES)

重复间隔必须大于或等于 PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,而灵活间隔必须大于或等于 PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS

    /**
     * The minimum interval duration for {@link PeriodicWorkRequest} (in milliseconds).
     */
    @SuppressLint("MinMaxConstant")
    public static final long MIN_PERIODIC_INTERVAL_MILLIS = 15 * 60 * 1000L; // 15 minutes.
    /**
     * The minimum flex duration for {@link PeriodicWorkRequest} (in milliseconds).
     */
    @SuppressLint("MinMaxConstant")
    public static final long MIN_PERIODIC_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes.

repeatInterval :重复的时间值
flexInterval:第二个时间值,

约束

约束可确保将工作延迟到满足最佳条件时运行。以下约束适用于 WorkManager

NetworkType 约束运行工作所需的网络类型。例如 Wi-Fi (UNMETERED)。
BatteryNotLow 如果设置为 true,那么当设备处于“电量不足模式”时,工作不会运行。
RequiresCharging 如果设置为 true,那么工作只能在设备充电时运行。
DeviceIdle 如果设置为 true,则要求用户的设备必须处于空闲状态,才能运行工作。在运行批量操作时,此约束会非常有用;若是不用此约束,批量操作可能会降低用户设备上正在积极运行的其他应用的性能。
StorageNotLow

如果设置为 true,那么当用户设备上的存储空间不足时,工作不会运行。

如需创建一组约束并将其与某项工作相关联,请使用一个 Contraints.Builder() 创建 Constraints 实例,并将该实例分配给 WorkRequest.Builder()

       val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.UNMETERED)
            .setRequiresCharging(true)
            .build()

        val myWorkRequest: WorkRequest =
            OneTimeWorkRequestBuilder<MyWorks>()
                .setConstraints(constraints)
                .build()

如果指定了多个约束,工作将仅在满足所有约束时才会运行。

如果在工作运行时不再满足某个约束,WorkManager 将停止工作器。系统将在满足所有约束后重试工作。

延迟:

如果您不希望工作立即运行,可以将工作指定为在经过一段最短初始延迟时间后再启动

al myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setInitialDelay(10, TimeUnit.MINUTES)
   .build()

这个延迟和handler的延迟机制是一样使用。PeriodicWorkRequest 设置初始延迟时间,在这种情况下,定期工作只有首次运行时会延迟。

重试和退避

如果您需要让 WorkManager 重试工作,可以从工作器返回 Result.retry()。然后,系统将根据退避延迟时间退避政策重新调度工作。

  • 退避延迟时间指定了首次尝试后重试工作前的最短等待时间。此值不能超过 10 秒(或 MIN_BACKOFF_MILLIS)。

  • 退避政策定义了在后续重试过程中,退避延迟时间随时间以怎样的方式增长。WorkManager 支持 2 个退避政策,即 LINEAR 和 EXPONENTIAL

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .setBackoffCriteria(
       BackoffPolicy.LINEAR,
       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
       TimeUnit.MILLISECONDS)
   .build()

最短退避延迟时间设置为允许的最小值,即 10 秒。由于政策为 LINEAR,每次尝试重试时,重试间隔都会增加约 10 秒。例如,第一次运行以 Result.retry() 结束并在 10 秒后重试;然后,如果工作在后续尝试后继续返回 Result.retry(),那么接下来会在 20 秒、30 秒、40 秒后重试,以此类推。如果退避政策设置为 EXPONENTIAL,那么重试时长序列将接近 20、40、80 秒,以此类推。

标记

在request的对象中,都支持setTag,方便我们在获取对象时,可以通标记值来获取。这个类似线程池获取某个线程一样,只要我们知道线程的名字,就能准确的找到

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
   .addTag("cleanup")
   .build()

数据绑定:

在处理异步操作时,必然和数据打交道,如何传递数据呢?通过Data来传递

通过request的setInputData来完成,我们在override fun doWork(): Result{}中,获取到

override fun doWork(): Result {

   //数据集合
   var data= inputData;

    return retry
}

同样,也可以将结果通过Resukt返回出去。

猜你喜欢

转载自blog.csdn.net/qq36246172/article/details/128952263