WorkManager 学习笔记

1,261 阅读4分钟

上周写了一篇Android 12适配笔记,其中有提到Android 12对应用在后台运行时启动ForegroundService做了更严苛的限制,建议使用WorkManager来替代。其实WorkManager早在19年初就推出了第一个稳定版,但是我之前一直没有使用过,正好趁这次机会学习一下。

WorkManager简介

WorkManager是处理后台任务的最新解决方案,最低兼容至Android 4.0,开发时就考虑了对电池续航的影响。不适用于应用关闭时就要终止的后台工作,以及需要立即执行的工作。

WorkManager有许多优点,个人感觉比较重要的有:

  • 工作约束条件 可以使用约束条件规定工作运行的最佳场景。例如,仅连接Wifi时、有足够的存储空间时。
  • 工作链 可以使用接口来串联各个工作任务,便于控制哪些任务先后执行,哪些任务并行执行。
  • 可靠性 已经调度的工作存储在WorkManager内置的Sqlite中,可以确保工作完成,即使中途设备重启,重启设备后WorkManager会自动继续。

WorkManager的简单使用

1. 在项目中引入WorkManager

在项目app module的build.gradle中的dependencies中添加依赖:

dependencies {
    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 - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"

    // optional - Multiprocess support
    implementation "androidx.work:work-multiprocess:$work_version"
}

2. 定义Worker类

继承Worker类,重写doWork()方法,在doWork()方法中编写需要执行的任务的代码,该方法的返回值会通知WorkManager Service工作是否成功,若失败是否重试。

class UploadWorker(context: Context, workerParameters: WorkerParameters)
    : Worker(context, workerParameters) {

    override fun doWork(): Result {
        //需要执行的任务的代码
        
        //工作完成
        return Result.success()
        //工作失败
        return Result.failure()
        //工作失败,进行重试
        return Result.retry()
    }
}

3. 创建与配置WorkRequest

定义了Worker类之后,通过WorkRequest来定义工作运行的方式和时间。

  • 创建WorkRequest WorkRequest分为一次性工作请求(OneTimeWorkRequest)和周期性工作请求(PeriodicWorkRequest):
        //一次性工作请求
        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            .build()
        //周期性工作请求
        val periodicWorkRequest: WorkRequest = PeriodicWorkRequestBuilder<UploadWorker>(
            //两次工作的间隔时间,时间单位为小时
            1, TimeUnit.HOURS,
            //临近间隔时间前工作开始的时间,时间单位为分钟
            15, TimeUnit.MINUTES
        )
            .build()
  • 创建Constraints(约束条件) 可以对WorkRequest添加以下几种约束条件,当满足条件时,工作才会执行:
        val constraints = Constraints.Builder()
            //设置网络类型 UNMETERED(Wifi) METERED(流量) NOT_REQUIRED(不限制)
            .setRequiredNetworkType(NetworkType.UNMETERED)
            //设置电量不足时是否限制运行工作 true(低电量时限制) false (不限制)
            .setRequiresBatteryNotLow(true)
            //设置是否仅在充电时运行工作 true(仅充电时运行) false(不限制)
            .setRequiresCharging(false)
            //设置否仅在设备空闲状态时运行工作 true(仅设备空闲时运行) false(不限制)
            .setRequiresDeviceIdle(false)
            //设置存储空间不足时是否限制运行工作 true(存储空间不足时限制) false(不限制)
            .setRequiresStorageNotLow(true)
            .build()

        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            .setConstraints(constraints)
            .build()
  • 设置延迟时间 使用如下代码来配置工作开始前的延迟时间:
        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            //设置延迟时间,单位为秒
            .setInitialDelay(10, TimeUnit.SECONDS)
            .build()
  • 设置重试参数 使用如下代码来配置工作失败重试的参数:
        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            //设置重试参数
            .setBackoffCriteria(
                //重试间隔时间的增长模式  LINEAR(如20 30 40)EXPONENTIAL(如 20 40 80)
                BackoffPolicy.LINEAR,
                //第一次重试的间隔时间
                OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                //时间单位
                TimeUnit.MILLISECONDS
            )
            .build()
  • 设置工作标签 使用如下方法配置工作的唯一标识,可以用于观察工作进度或取消工作:
        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            //添加唯一标识
            .addTag("upload log")
            .build()
  • 传入参数 如下代码展示了如何配置需要传入到Worker的参数,以及如何获取:
        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            //设置传入的参数
            .setInputData(workDataOf("UPLOAD_PATH" to "https://..", "DATA" to "..."))
            .build()
                
class UploadWorker(context: Context, workerParameters: WorkerParameters)
    : Worker(context, workerParameters) {

    override fun doWork(): Result {
        //获取传入的参数
        val uploadPath = inputData.getString("UPLOAD_PATH") ?: return Result.failure()
        val data = inputData.getString("DATA") ?: return Result.failure()

        return Result.success()
    }
}
  • 提交WorkRequest 使用如下代码提交WorkRequest至WorkManager:
        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            .build()
        WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)

4. 获取工作的信息

可以通过如下代码来获取工作的信息:

        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            .build()
        val workInfo = workManager.getWorkInfoById(oneTimeWorkRequest.id).get()
        //id
        workInfo.id
        //状态
        workInfo.state
        //标签
        workInfo.tags
        //Result.success() Result.failure() 设置的输出参数
        workInfo.outputData

或者可以通过如下代码实时监听工作的状态:

        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            .build()
        workManager.getWorkInfoByIdLiveData(oneTimeWorkRequest.id).observe(lifecycleOwner, { workInfo ->
            //id
            workInfo.id
            //状态
            workInfo.state
            //标签
            workInfo.tags
            //Result.success() Result.failure() 设置的输出参数
            workInfo.outputData
        })

5. 取消工作

可以通过如下代码取消工作:

        val oneTimeWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
            .build()
        //取消指定的worker
        workManager.cancelWorkById(oneTimeWorkRequest.id)
        
        //取消所有work
        workManager.cancelAllWork()