Jetpack WorkManager 和 Kotlin 春节社会实践

1,390 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战

一、WorkManager

WorkManager 是持久工作的推荐解决方案。当通过应用程序重启和系统重启保持计划时,工作是持久的。由于大多数后台处理最好通过持久性工作来完成,WorkManager 是后台处理的主要推荐API。

使用 WorkManager 注册的周期性任务不一定会准时执行,这不是Bug,而是系统为了减少电量消耗可能会将触发事件接近的几个任务放在一起执行,这样可以大幅度减少CPU唤起次数,从而有效延长电池时间。

注意:WorkManager 和 Seriver 不是一个概念,也没有直接联系。Seriver 是Android系统的四大组件之一。WorkManager 只是一个处理定时任务的工具。

一些概念在上一遍已经有了这里就不说了,直接开始使用 Kotlin 实践吧。

二、WorkManager 基本用法

2.1 添加依赖

将以下依赖项添加到app/build.gradle文件中:

dependencies {
    def work_version = "2.7.1"

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

2.2 使用 WorkManager

2.2.1 定义任务

定义任务必须继承自 Worker 类,并调用它的构造方法(唯一)。重写 doWork() 方法。

注意:doWork() 方法 在 WorkManager 提供的后台线程上异步运行,因此你可以放心的在这里执行耗时操作。

/**
 * 创建人:帅次
 * 创建时间:2022/1/27
 * 功能:定义任务(Kotlin)
 */
class KotlinTestWork(appContext: Context, workerParams: WorkerParameters):
    Worker(appContext, workerParams) {
    override fun doWork(): Result {
        //执行耗时操作
        doSmothing()
        return Result.success()
    }

    private fun doSmothing() {
        //这里仅仅简单打印一下
        Log.e("KotlinTestWork","KotlinTestWork 在执行 doWork ")
    }
}

从 doWork() 返回的 Result 通知 WorkManager 服务工作是否成功,以及在失败的情况下是否应该重试工作:

  • Result.success():成功。
  • Result.failure():失败。
  • Result.retry():工作失败,可以结合 WorkRequest.Builder 的 setBackoffCriteria() 方法重新执行任务。

2.2.2 构建任务请求

使用 WorkRequest.Worker 定义了工作单元,而 WorkRequest(及其子类)定义了它应该如何以及何时运行。在最简单的情况下,你可以使用 OneTimeWorkRequest。

        //构建任务请求
        //方法一:不需要额外配置的简单Work
        val fromWorkRequest: WorkRequest = OneTimeWorkRequest.from(KotlinTestWork::class.java)
        //方法二:复杂的Work,可使用构建器进行配制
        val workRequest: WorkRequest =
            OneTimeWorkRequestBuilder<KotlinTestWork>().build()

2.2.3 向系统提交 WorkRequest

最后,使用 enqueue() 方法将 WorkRequest 构建的任务提交给 WorkManager。系统会在合适的时间去运行。

        binding.btnDowork.setOnClickListener {
            //向系统提交 WorkRequest
            WorkManager
                .getInstance(this)
                .enqueue(workRequest)
        }

三、WorkManager 进阶用法

3.1 任务

  • 观察任务
  • 传值
  • 约束条件
    @RequiresApi(Build.VERSION_CODES.N)
    fun complexWork(){
        //约束条件
//        val constraints = Constraints.Builder().apply {
//            setRequiresDeviceIdle(true)//触发时设备是否为空闲
//            setRequiresCharging(true)//触发时设备是否充电
//            setRequiredNetworkType(NetworkType.UNMETERED)//触发时网络状态
//            setRequiresBatteryNotLow(true)//指定设备电池是否不应低于临界阈值
//            setRequiresStorageNotLow(true)//指定设备可用存储是否不应低于临界阈值
////            addContentUriTrigger(myUri,false)//指定内容{@link android.net.Uri}时是否应该运行{@link WorkRequest}更新
//        }.build()
        //传值
        val data = Data.Builder().apply {
            putString("name","Scc")
            putInt("age",25)
        }.build()
        //构建任务
        complexWorkRequest =
            OneTimeWorkRequestBuilder<KotlinTestWorkInfo>()
                //1分钟后执行,当然你也可以用此方法指定单位(毫秒/秒/分钟/小时/天)
                .setInitialDelay(1, TimeUnit.SECONDS)
                .addTag("complex")
//                .setConstraints(constraints)
                .setInputData(data)
                .build()
        binding.btnObserveWorkinfo.setOnClickListener {
            Log.e("Work","start")
            val workManager = WorkManager.getInstance(this)
            workManager.getWorkInfoByIdLiveData(complexWorkRequest.id)
                .observe(this){
                    Log.e("Work","State:"+it.state)
                    if (!it.outputData.getString("work").isNullOrBlank()){
                        var msg = it.outputData.getString("work") +":"+it.outputData.getInt("length",5)
                        Log.e("Work","Data:"+msg)
                    }
                }
            workManager.enqueue(complexWorkRequest)
        }
    }

3.2 取消或停止任务

  • 通过 Id 取消任务
  • 通过 Tag 取消任务
  • 取消所有任务
            WorkManager.getInstance(this).cancelAllWorkByTag("complex")
            WorkManager.getInstance(this).cancelWorkById(complexWorkRequest.id)
            WorkManager.getInstance(this).cancelAllWork()

3.3 链式任务

假设咱们有三个独立的后台任务:获取图片,压缩图片和上传图片。那么我们想要实现这个功能就可以使用链式任务来搞定。

        //链式调用
        WorkManager.getInstance(this)
            //并行运行
            .beginWith(listOf(work1, work2, work3))
            //执行完签名的操作继续调用压缩任务
            .then(cache)
            //执行完压缩任务调用上传任务
            .then(upload)
            //添加到WorkManager队列中
            .enqueue()
  • beginWith:beginWith()方法表示开始一个链式任务。
  • then:后面不管什么任务都用then()方法来链接即可。

本篇文章更多的是使用Kotlin来实践 WorkManager 更多的概念描述和Java实践可以去看看 # Jetpack WorkManager 一起来尝试一下吧?