Android(Kotlin)Jetpack组件之WorkManager使用与API

你若需要时间,还得自己把他造出来。 喝汤能补 (* ^ ▽ ^ *)

前言

  该文章作为学习交流,如有错误欢迎各位大佬指正 (* ^ ▽ ^ *)

  • 本文简介
    主要讲解:WorkManager的使用,以及相关API的使用。

概述

  在介绍WorkManager前,先来了解下Android系统的后台历史。在早期的时候,Android系统后台功能非常开放,优先级高,仅次于Activity,所以每个应用都想无限地占用后台资源,导致手机内存紧张,耗电也快,以及越发卡。后期Android系统每发布一个新版本,后台权限都会被限制。

  • 4.4系统开始AlarmManager的触发时间由原来的精准变为不精准;5.0系统中加入了JobScheduler来处理后台任务;6.0系统中引入Doze和App Standby模式用于降低手机被后台唤醒的频率;从8.0系统开始直接禁用了Service的后台功能,只允许使用前台Service。
  • 在国产手机上,WorkManager功能可能得不到正确运行。因为多数厂商手机在定制系统时,会增加一键关闭的功能,允许用户杀死所以非白名单的应用。被杀死的的应用就无法接受广播,也就无法运行WorkManager后台任务。
  • WorkManager可以用,但不要使用它实现核心功能,因为在国产手机上可能非常不稳定。

虽然,这样能不断优化Android系统的卡顿问题,但是也导致开发者很难在不同的系统版本上为应用进行兼容处理。这时,就需要使用WorkManager来进行简化。

  WorkManager组件,适合用于处理一些要求定时执行的任务,它能根据系统的版本自动选择底层使用AlarmManager还是JobScheduler实现,从而减少开发者的兼容工作。还支持周期性任务、链式任务处理等功能。

  • WorkManager与Service并不相同,没有直接联系。Service是Android系统四大组件之一,没有被销毁的情况下是一直保持在后台运行的。WorkManager是一个处理定时任务的工具,可以保证在应用退出,或手机重启下,之前注册的任务仍会执行。
  • WorkManager很适合执行一些定期和服务器进行交互的任务,比如周期性地同步数据等场景
  • WorkManager注册的周期性任务不能保证一定会准时执行,因系统为了减少电量消耗和CPU被唤醒的次数,可能会将触发时间临近的几个任务放在一起执行。
  • 使用步骤:
    (1)自定义后台任务类,必须继承Worker,并调用唯一的构造函数,重写doWork()方法,该方法中就是具体的任务逻辑。
    (2)然后使用WorkRequest的子类构建后台任务的运行条件。
    (3)将该后台任务请求传入WorkManage的enqueue() 方法中,系统在合适时间运行。WorkManager对象需要WorkManager.getInstance(Context对象)得到
  • doWork() 不在主线程中,可执行耗时任务。要求返回Result对象,成功是Result.success();失败是Result.failure();UI层可通过WorkManager中的getWorkInfoByIdLiveData()函数进行来监听成功与失败。Result.retry()也是失败,不过可结合WorkRequest的setBackoffCriteria()函数重新执行任务。
  • OneTimeWorkRequest是WorkRequest的子类,用于构建单次运行的后台任务请求。OneTimeWorkRequest.Builder(自定义后台类的Class对象).build()
  • PeriodicWorkRequest是WorkRequest的子类,用于构建周期性运行的后台任务请求。且因降低设备性能消耗,周期性间隔不能短于15分钟。PeriodicWorkRequest.Builder(自定义后台类的Class对象,周期性间隔时间,时间的单位).build()
  • setInitialDelay(延迟时间,时间的单位) 让后台任务在指定延迟时间后运行。
  • addTag(标签的名称) 用于给后台任务请求添加标签。标签的主要作用,可以通过标签来取消后台任务请求,只有是该标签的任务都可以取消
  • 取消后台任务,WorkManager类中的cancelAllWorkByTag(请求任务的标签)cancelWorkById(请求任务的对象的id)cancelAllWork() 取消所以后台任务。WorkManager的对象,使用WorkManager.getInstance(Context对象)得到。
  • setBackoffCriteria() ,当doWork()方法返回Result.retry()时,可以通过该方法请求执行任务。该方法的参数:第一个是用于指定如果任务再次执行失败,下次重试的时间以什么样的形式延迟;第二个和第三个参数,用于指定多久之后重新执行任务,时间最短不少于10秒钟。第一个参数的值:LINEAR代表下次重试时间以线性方式延迟EXPONENTIAL代表下次重试时间以指数的 方式延迟
    如果任务一直失败,那重试就无意义,这时频繁重试就会增加设备消耗。如果失败次数增多,重试时间也进行延迟,就能合理的降低性能消耗
  • WorkManager中的getWorkInfoByIdLiveData(请求任务的对象的id)getWorkInfosByTagLiveData(请求任务的标签) 来监听请求任务执行结果(Result的State中的状态)
  • WorkManager中的链式调用,beginWith开启一个链式任务,then连接任务。必须在前一个后台任务执行成功后,下一个任务才会执行。 如果某个任务执行失败,或者被取消,则后面的任务都不会执行。
WorkManager.getInstance(Context对象)
                .beginWith(请求任务WorkRequest子类对象)
                .then(请求任务WorkRequest子类对象)
                .then(请求任务WorkRequest子类对象)
                .enqueue()

基本使用

依赖库

在app/build.gradle文件中添加依赖库。

android {
//...
}

dependencies {
    implementation "androidx.work:work-runtime:2.4.0"
}

简单后台任务使用

大致的使用步骤
(1)定义一个后台任务,并实现具体的任务逻辑
自定义后台任务类,必须继承Worker,并调用唯一的构造函数,重写doWork()方法,该方法中就是具体的任务逻辑。
(2)配置后台任务的运行条件和约束信息,并构建后台任务请求
分为两种方式:
OneTimeWorkRequest是WorkRequest的子类,用于构建单次运行的后台任务请求。
PeriodicWorkRequest是WorkRequest的子类,用于构建周期性运行的后台任务请求。且因降低设备性能消耗,周期性间隔不能短于15分钟。

val request = OneTimeWorkRequest.Builder(SimpleWorker::class.java).build()

val requestTime = PeriodicWorkRequest.Builder(SimpleWorker::class.java,15,
            TimeUnit.MINUTES).build()

(3)将该后台任务请求传入WorkManage的enqueue()方法中,系统在合适时间运行。
使用WorkManager.getInstance(Context对象).enqueue(WorkRequest子类的实例对象)

简单示例代码
主要功能:定义后台任务,并打印一段日志。

class SimpleWorker(context: Context,params: WorkerParameters): Worker(context,params) {
    override fun doWork(): Result {
        Log.e("bluePlus"," do work in SimpleWorker ")
        return Result.success()
    }
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_work_manager)

        doWorkBtn.setOnClickListener {
            // 单次请求任务
            val request = OneTimeWorkRequest.Builder(SimpleWorker::class.java).build()
            // 周期性请求任务
            val requestTime = PeriodicWorkRequest.Builder(SimpleWorker::class.java,15,
                TimeUnit.MINUTES).build()
            WorkManager.getInstance(applicationContext).enqueue(request)
        }
    }

业务复杂后台任务使用

  在复杂的业务面前,需要编写对应的后台任务处理逻辑。比如:延时后台任务的处理,取消后台任务后台任务重新执行等等

  • setInitialDelay(延迟时间,时间的单位) 让后台任务在指定延迟时间后运行。
  • addTag(标签的名称) 用于给后台任务请求添加标签。标签的主要作用,可以通过标签来取消后台任务请求,只有是该标签的任务都可以取消
  • 取消后台任务,WorkManager类中的cancelAllWorkByTag(请求任务的标签)cancelWorkById(请求任务的对象的id)cancelAllWork() 取消所以后台任务。WorkManager的对象,使用WorkManager.getInstance(Context对象)得到。
  • setBackoffCriteria() ,当doWork()方法返回Result.retry()时,可以通过该方法请求执行任务。该方法的参数:第一个是用于指定如果任务再次执行失败,下次重试的时间以什么样的形式延迟;第二个和第三个参数,用于指定多久之后重新执行任务,时间最短不少于10秒钟。第一个参数的值:LINEAR代表下次重试时间以线性方式延迟EXPONENTIAL代表下次重试时间以指数的 方式延迟
    如果任务一直失败,那重试就无意义,这时频繁重试就会增加设备消耗。如果失败次数增多,重试时间也进行延迟,就能合理的降低性能消耗
  • WorkManager中的getWorkInfoByIdLiveData(请求任务的对象的id)getWorkInfosByTagLiveData(请求任务的标签) 来监听请求任务执行结果(Result的State中的状态)
  • WorkManager中的链式调用,beginWith开启一个链式任务,then连接任务。必须在前一个后台任务执行成功后,下一个任务才会执行。 如果某个任务执行失败,或者被取消,则后面的任务都不会执行。
WorkManager.getInstance(Context对象)
                .beginWith(请求任务WorkRequest子类对象)
                .then(请求任务WorkRequest子类对象)
                .then(请求任务WorkRequest子类对象)
                .enqueue()

简单的例子了解相关方法的用法
主要的是了解相关方法是如何调用的。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_work_manager)

        // 单次请求任务
        val request = OneTimeWorkRequest.Builder(SimpleWorker::class.java)
//            .setInitialDelay(5,TimeUnit.MINUTES) //延时处理
            .addTag("simple") //添加标签
            .setBackoffCriteria(BackoffPolicy.LINEAR,10,TimeUnit.MINUTES)
            .build()
        // 周期性请求任务
        val requestTime = PeriodicWorkRequest.Builder(SimpleWorker::class.java,15,
            TimeUnit.MINUTES).build()

        doWorkBtn.setOnClickListener {
            //1.WorkManager的普通调用
            WorkManager.getInstance(applicationContext).enqueue(request)
//            WorkManager.getInstance(applicationContext).cancelAllWorkByTag("simple") //通过标签取消
//            WorkManager.getInstance(applicationContext).cancelWorkById(request.id) //通过id取消
//            WorkManager.getInstance(applicationContext).cancelAllWork() //取消全部任务

            //2.WorkManager的链式调用
            val sync = OneTimeWorkRequest.Builder(SimpleWorker::class.java).build()
            val compress = OneTimeWorkRequest.Builder(SimpleWorker::class.java).build()
            val upload = OneTimeWorkRequest.Builder(SimpleWorker::class.java).build()
            WorkManager.getInstance(this)
                .beginWith(sync)
                .then(compress)
                .then(upload)
                .enqueue()
        }

        // 监听请求任务的结果
        WorkManager.getInstance(this).getWorkInfoByIdLiveData(request.id)
            .observe(this){ workInfo ->
                if (workInfo.state == WorkInfo.State.SUCCEEDED){
                    Log.e("bluePlus"," do work succeeded ")
                }else if (workInfo.state == WorkInfo.State.FAILED){
                    Log.e("bluePlus"," do work Failed ")
                }
            }
    }
}


class SimpleWorker(context: Context,params: WorkerParameters): Worker(context,params) {
    override fun doWork(): Result {
        Log.e("bluePlus"," do work in SimpleWorker ")
//        return Result.retry()
//        return Result.failure()
        return Result.success()
    }
}

// UI界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/doWorkBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Do Work"/>

</LinearLayout>

觉得有帮助的点下赞哟,毕竟三连步骤更多,嘻嘻,谢谢大家的支持(* ^ ▽ ^ *)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值