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

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

END

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 本文主要内容 WorkManager使用详细介绍自定义Worker的几种实现使用注意事项 特性 兼容Android...
    葫芦娃大战屎壳郎阅读 1,956评论 0 1
  • 背景:通常我们在开发过程中处理后台任务的时候可能是自己维系一个线程池或者通过一个后台任务来完成我们的工作,然后对于...
    o蚂蚁上树o阅读 1,759评论 0 50
  • Workmanager是jetpack系列及其重要的一部分,他可以让用户设定定时任务,并设定一些条件,条件符合并到...
    坑逼的严阅读 682评论 0 1
  • WorkManager架构组件是用来管理后台工作任务。这个时候你可能会奇怪了Android不是已经 有很多管...
    tuacy阅读 6,449评论 4 14
  • 前言 前面的内容中我们已经介绍了很多Jetpack中的架构组件,可以说每一种组件的出现都是为了更好的解决现在存在的...
    rivenlee阅读 745评论 0 1