Jetpack 之 WorkManager 小白入手

简介:

  WorkManager 是一个 API,它可以很合理的安排可延迟的异步任务,即使应用程序退出或者设备重新启动,这些异步任务也有望运行.WorkManager API是所有以前Android 后台调度api 的合适的且推荐的替代品,包括FirebaseJobDispatcher.GcmNetworkManager,和 Job Scheduler.WorkManager 在现在,一致的 api 中合并了其前辈的功能,该 API 可以兼容到 API 14,同事考虑了电池的寿命.
虽然 Service也可以实现,但是消耗电量大,而且并不允许长时间后台执行.PASS 掉.
特点

  • 不需要及时完成的任务.比如 发送日志,同步用户数据等
  • 保证任务一定会被执行.即使 app不在运行或者重启设备.
  • 兼容范围广.最低到API level 14.并且不需要安装 google paly service.

原理:

image.png

使用方法:

先看看几个关键的类.
Worker : 任务的执行者,是一个抽象类,需要集成它来实现要执行的任务.
WorkRequest : 指定哪个 Worker 执行任务,可以向WorkRequest中添加细节,指定执行环境,执行顺序,ID 等.WorkRequest是个抽象类,在代码中是,使用其子类,OneTimeWorkRequest 或者PeriodicWorkRequest.
WorkManager :对WorkRequest进行排队和管理.
WorkStatus :包含任务的状态和信息,以 LIiveData 的形式提供给观察者.

1,build.gradle 添加依赖

    // Java
    implementation "androidx.work:work-runtime:2.5.0"
    // kotlin  workmanager
    implementation "androidx.work:work-runtime-ktx:2.5.0"

2,使用 Work 类定义任务

class MyWoker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {

        //耗时任务在 doWork()中执行
        return Result.success()
    }
}

doWork() 有 3 种返回类型

  • 执行成功 Result.success()
  • 执行失败 Result.failure()
  • 重新执行 Result.retry()

3, 使用 WorkRequest 分配任务

  WorkRequest是一个抽象类,它有两种实现方式,OneTimeWorkRequest 和 PeriodicWorkRequest,分别对应一次性任务和周期性任务.

定义WorkRequest
OneTimeWorkRequest :

 var build = OneTimeWorkRequest.Builder(MyWoker::class.java).build()

PeriodicWorkRequest :

 var build = PeriodicWorkRequest.Builder(MyWoker::class.java, 15, TimeUnit.MINUTES).build()

以下的代码示例中,我会以OneTimeWorkRequest写 Demo.
PeriodicWorkRequest使用和OneTimeWorkRequest没有太大区别,需要注意的是,间隔时间不能少于 15 分钟.
设置任务的触发条件:
  比如,我们在设备处于充电,网络连接的情况下触发任务,通过.setConstraints(constraints)方法设置触发条件

        var constraints = Constraints.Builder()
             .setRequiresCharging(true)
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .build()

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .build()

  看下图还有很多其他的条件,具体使用什么条件,根据需求定吧.

image.png

设置任务延迟:
  通过.setInitialDelay(10,TimeUnit.SECONDS) 设置延时条件

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .setInitialDelay(10,TimeUnit.SECONDS)
            .build()

设置指数退避策略:
  假如Work线程执行异常,在 doWork()方法中返回 Result.retry(),系统会有默认的的指数退避策略来重试任务.也可以通过.setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.MINUTES)来定义指数退避策略.BackoffPolicy有两个值LINEAR(每次重试的时间线性增加,比如第一次10分钟,第二次就是20分钟)、EXPONENTIAL(每次重试时间指数增加)。

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .setInitialDelay(10,TimeUnit.SECONDS)
            .setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.MINUTES)
            .build()

为任务设置 tag 标签:
  设置 tag 标签后,可以根据 tag 来跟踪任务的状态:WorkManager.getInstance(this).getWorkInfosByTag(),也可以取消任务: WorkManager.getInstance(this).cancelAllWorkByTag().

        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setConstraints(constraints)
            .setInitialDelay(10,TimeUnit.SECONDS)
            .setBackoffCriteria(BackoffPolicy.LINEAR,OneTimeWorkRequest.MIN_BACKOFF_MILLIS,TimeUnit.MINUTES)
            .addTag("myTag")
            .build()

4, 将任务交给系统,加入任务队列

        WorkManager.getInstance(this).enqueue(build)

观察任务状态:
  观察任务的状态的方法如下:

image.png

  我们可以通过 LivaData 在任务状态发生变化的的时候接收通知:

        WorkManager.getInstance(this)
            .getWorkInfosByTagLiveData("myTag")
            .observe(this,
                {
                    Log.e("TestActivity", "workInfo: $it")
                })

取消任务:
  取消任务的方法如下:

image.png

  与观察任务类似,可以根据 id 或者 tag 来取消某个任务或者取消所有任务.

        WorkManager.getInstance(this).cancelAllWorkByTag("myTag")

5, WorkManager 和 Worker 之间的参数传递

  WorkManager通过setInputData()方法给 Worker 传递参数.数据的传递通过 Data 对象来完成.
  ⚠️ Data 只能用于传递一些小的数据类型,切数据不能超过 10KB.

        var inputData = Data.Builder().putString("nameS", "张三").build()
        var build = OneTimeWorkRequest.Builder(MyWoker::class.java)
            .setInputData(inputData)
             //......
            .addTag("myTag")
            .build()

  Woker 通过 getInputData()方法接受数据,并在任务完成后,向 WorkManager 返回数据.

class MyWoker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        inputData.getString("nameS")?.let { Log.e("mmm", "MyWoker收到的信息: $it") }
        var outData = Data.Builder().putString("nameM", "我已经回复张三了").build()
        return Result.success(outData)
    }
}

  WorkManager通过 LiveData 得到从 Worker 返回数据

        WorkManager.getInstance(this)
            .getWorkInfosByTagLiveData("myTag")
            .observe(this, {
                for (workInfo in it) {
                    Log.d("mmm", workInfo.toString())
                    if (WorkInfo.State.SUCCEEDED.isFinished) {
                        val outputData = workInfo.outputData
                        val nameM = outputData.getString("nameM")
                        nameM?.let { it1 ->
                            Log.e("mmm", "TestActivity收到的信息: $it1")
                            WorkManager.getInstance(this@TestActivity).cancelAllWorkByTag("myTag")
                        }

                    }
                }
            })

   执行结果截图:


image.png

6, 任务链

   如果有一系列的任务需要按照顺序执行,那么可以利用WorkManager.beginWith().then().then()....enqueue()的方式构建任务.beginWith()可与传递单个任务,也可以传递任务集合.

image.png

单个任务:

        WorkManager.getInstance(this)
            .beginWith(build)
            .then(build)
            .then(build)
            .enqueue()

多个任务:(集合)
   WorkContinuation.combine()方法将任务链组合起来用

        var buildOne = WorkManager.getInstance(this)
            .beginWith(buildOne)
            .then(buildTwo)
        var buildTwo = WorkManager.getInstance(this)
            .beginWith(buildThree)
            .then(buildFour)
        var list = mutableListOf()
        list.add(buildOne)
        list.add(buildTwo)
        WorkContinuation
            .combine(list)
            .then(buildFive)
            .enqueue()

ps:任务链的东西,我没试过

END

你可能感兴趣的:(Jetpack 之 WorkManager 小白入手)