WorkManager

一、概述

WorkManager是针对一些即使App退出了也要由系统确保运行的任务设计的,可以延迟执行后台任务,提供了电量友好型API

WorkManager可以轻松让异步任务延迟执行以及何时运行他们。我们可以给WorkManager设置一个任务,然后选择相应运行的环境,并在符合条件时将其交给WorkManager运行,即使该应用被强制退出,此任务仍可保证运行。

WorkManager在应用运行时执行任务会开一个新线程执行,在应用未运行时会自动选择JobScheduler、Firebase JobDispatcher或AlarmManager。WorkManager会自动选择最佳选项

二、依赖

dependencies {
    // (Java only)
    implementation 'androidx.work:work-runtime:2.5.0'

    // Kotlin + coroutines
    implementation 'androidx.work:work-runtime-ktx:2.5.0'

    // optional - RxJava2 support
    implementation 'androidx.work:work-rxjava2:2.5.0'

    // optional - GCMNetworkManager support
    implementation 'androidx.work:work-gcm:2.5.0'

    // optional - Test helpers
    androidTestImplementation 'androidx.work:work-testing:2.5.0'

    // optional - Multiprocess support
    implementation 'androidx.work:work-multiprocess:2.5.0'
}

三、内部类

· Worker:指定我们需要执行的任务

· WorkRequest:代表一个单独具体的任务。一个WorkRequest对象指定某个Worker类应该执行该任务。同时可以向WorkRequest对象中添加详细信息,指定任务运行的环境。每个WorkManager都有一个自动生成的唯一ID,我们可以使用此ID执行取消排队或者获取任务状态等内容。我们一般使用WorkManager的子类:OneTimeWorkRequest或PeriodicWorkRequest

· WorkRequest.Builder:用于创建WorkRequest对象。常用OneTimeWorkRequest.Builder或PeriodicWorkRequest.Builder

· Constraints:指定任务何时何状态运行。我们通过Constraints.Builder创建Constraints对象,并在创建WorkRequest前将Constraints对象传递给WorkRequest.Builder

· WorkManager:将WorkRequest入队并管理。我们将WorkRequest对象传递给WorkManager,由WorkManager同意调度并遵守我们约定的约束条件

· WorkStatus:包含有关特定任务的信息。WorkManager为每个WorkRequest对象提供一个LiveData,LiveData持有一个WorkStatus,通过观察LiveData确认任务的当前状态

四、基本用法

基本用法分为3步:

  1. 定义后台任务,并实现相关逻辑
  2. 配置该后台任务的运行条件和约束条件
  3. 构建后台任务请求

定义后台任务,并实现相关逻辑

定义自己的Worker类继承自Worker类并重写doWork方法

doWork方法指定Worker类如何执行操作,但是不能出现任何关于任务何时运行的信息

class myWorker(context: Context, params: WorkerParameters) : Worker(context, params){
    override fun doWork() : Result{
        //执行操作
        return Result.success()
    }
}

配置该后台任务的运行条件和约束条件

在MainActivity中根据myWorker类创建OneTimeWorkRequest对象

val myConstraints = Constraints.Builder().build()
val myRequest = OneTimeWorkRequest.Builder(myWorker::class.java)
                                  .setConstraints(myContraints)
                                  .build()

OneTimeWorkRequest.Builder用于构建单次运行的后台任务请求

PeriodicWorkRequest.Builder用于构建周期运行的后台任务请求,且运行间隔不能短于15 mins

在创建Constraints和创建WorkRequest时可以配置各种各样的运行条件和约束条件

构建后台任务请求

在MainActivity中将该后台任务请求传入WorkManager的enqueue方法。

WorkManager.getInstance(this).enqueue(myRequest)

检查任务状态方法:

 WorkManager.getInstance(this).getWorkInfoByIdLiveData(myRequest.id)
                              .observe(this){ workInfo ->
 	if (workInfo.state == WorkInfo.State.SUCCEEDED){
                //利用workInfo对结果进行判断
    }
}

取消任务方法:

WorkManager.getInstance(this).cancelByWorkId(myRequest.id)

整体如下:

class MainActivity : AppcompatActivity(){
    @SuppressLint("EnqueueWork")
    override fun onCreate(saveInstanceState: Bundle?){
        ...
        val myConstraints = Constraints.Builder().build()
        val myRequest = OneTimeWorkRequest.Builder(myWorker::class.java)
                                          .setConstraints(myContraints)
                                          .build()
        WorkManager.getInstance(this).enqueue(myRequest)
         WorkManager.getInstance(this).getWorkInfoByIdLiveData(myRequest.id)
                              .observe(this){ workInfo ->
 			if (workInfo.state == WorkInfo.State.SUCCEEDED){
                //利用workInfo对结果进行判断
    		}
		}
        WorkManager.getInstance(this).cancelByWorkId(myRequest.id)
        
    }
}

含参Worker类

使用键值对和Data对象进行参数的输入和结果的返回。

在主函数中通过观察任务的WorkStatus获取输出

TestWorker类

class TestWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    companion object{
        const val KEY_INT_ARG = "INT"
        const val KEY_STR_ARG = "STR"
        const val KEY_LIST_ARG = "LIST"
        const val KEY_CLASS_ARG = "CLASS"
        const val KEY_RESULT = "RESULT"
    }

    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {
        //获取参数
        val int = inputData.getInt(KEY_INT_ARG, 0)
        println("int:$int.toString()")
        val str = inputData.getString(KEY_STR_ARG)
        /**
         * 仅传递基础数据类型和其构成的数组
         * 对于类和类组成的数组,需要使用Gson转换成json字符串
         * Gson依赖:implementation 'com.google.code.gson:gson:2.8.6'
         */
        val list: ArrayList<TestClass> = Gson().fromJson(
            inputData.getString(KEY_LIST_ARG),
            object : TypeToken<ArrayList<TestClass>>() {}.type
        )
        val cls: TestClass = Gson().fromJson(
            inputData.getString(KEY_CLASS_ARG),
            object : TypeToken<TestClass>() {}.type
        )

        //对参数进行操作
        println("TestWorker:")
        println("int:$int.toString()")
        println("str:$str")
        for (item in list){
            println("list:${item.text}")
        }
        println("class:${cls.text}")

        //返回值
        val listString = Gson().toJson(list)
        val result = Data.Builder().putString(KEY_RESULT, listString).build()
        return Result.Success(result)
    }
}

主函数

class MainActivity : AppCompatActivity() {
    @SuppressLint("EnqueueWork")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //非基本类型参数转换成String
        val cls = TestClass("TestClass")
        val clsString = Gson().toJson(cls)
        val list = ArrayList<TestClass>()
        list.add(TestClass("TestClass1"))
        list.add(TestClass("TestClass2"))
        list.add(TestClass("TestClass3"))
        val listString = Gson().toJson(list)
        //创建参数
        val myData = Data.Builder().putInt(TestWorker.KEY_INT_ARG, 999)
                                   .putString(TestWorker.KEY_STR_ARG, "String")
                                   .putString(TestWorker.KEY_CLASS_ARG, clsString)
                                   .putString(TestWorker.KEY_LIST_ARG, listString)
                                   .build()
        //构建后台
        val work = OneTimeWorkRequest.Builder(TestWorker::class.java)
                                     .setInputData(myData)
                                     .build()
        WorkManager.getInstance(this).enqueue(work)
        //获得返回值
        WorkManager.getInstance(this).getWorkInfoByIdLiveData(work.id)
                                     .observe(this){workInfo ->
            val str = workInfo.outputData.getString(TestWorker.KEY_RESULT)
            if (str != null){
                val result: ArrayList<TestClass> = Gson().fromJson(str, object : TypeToken<ArrayList<TestClass>>() {}.type)
                for (item in result){
                    println("result:${item.text}")
                }
            }
        }
    }
}

链式任务

WorkManager允许我们创建和排队多个任务的工作序列,以及它们按照什么顺序运行。

任何一个任务返回Work.WorkResult.FAILURE,整个序列结束

WorkManager.getInstance(this).beginWith(workA)
                             .then(workB)
                             .then(workC)
                             .enqueue()

允许多个对象传递给begin()和then()

WorkManager并行运行同一次方法传进的任务

WorkManager.getInstance(this).beginWith(listOf(workerA1, workerA2, workerA3))
                             .then(listOf(workerB1, workerB2))
                             .then(workerC)
                             .enqueue()

允许使用WorkContinuation.combine方法连接多个链

WorkManager根据连接链的顺序依次运行。

链内任务按顺序执行

链间任务可能重叠导致任务顺序的改变。

 val chain1 = WorkManager.getInstance(this)
                         .beginWith(workerA1)
                         .then(workerB1)
val chain2 = WorkManager.getInstance(this)
                        .beginWith(workerA2)
                        .then(workerB2)
WorkContinuation.combine(listOf(chain1, chain2))
                .then(workerC)
                .enqueue()
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐