美文网首页
Jetpack 之 WorkManager 小白入手

Jetpack 之 WorkManager 小白入手

作者: 鹅鹅鹅曲项向天歌呀 | 来源:发表于2021-07-01 08:26 被阅读0次

    🍓 简介:

      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<WorkContinuation>()
            list.add(buildOne)
            list.add(buildTwo)
            WorkContinuation
                .combine(list)
                .then(buildFive)
                .enqueue()
    

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

    END

    相关文章

      网友评论

          本文标题:Jetpack 之 WorkManager 小白入手

          本文链接:https://www.haomeiwen.com/subject/xlbpjltx.html