• 【Android-Jetpack进阶】6、WorkManager 后台线程、一次性、周期性、任务链的 Work


    六、WorkManager 后台线程

    WorkManager 用于 App 中不需要及时完成的任务(如上报日志、同步数据),因为将任务落盘到数据库故其保证即使设备重启、App 彻底退出,都依然会执行,其省电,兼容几乎所有设备(高版本用 JobScheduler,低版本用 AlarmManager,最终都是用 Adnroid 的 Executor 执行的),架构如下图。

    在这里插入图片描述

    首先,新建项目,项目github地址详见,在 build.gradle(app) 添加如下依赖:

        def work_version = "2.7.1"
        implementation "androidx.work:work-runtime-ktx:$work_version"
    

    然后,新建UploadLogWorker 类,负责上报日志,代码如下:

    package com.bignerdranch.android.jetpack6workmanagertest
    
    import android.content.Context
    import android.util.Log
    import androidx.work.Data
    import androidx.work.Worker
    import androidx.work.WorkerParameters
    
    
    // 上传日志的Worker
    class UploadLogWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
        /**
         * 耗时的任务,在doWork()方法中执行
         *
         * 执行成功返回Result.success()
         * 执行失败返回Result.failure()
         * 需要重新执行返回Result.retry()
         */
        override fun doWork(): Result {
            //接收外面传递进来的数据
            val inputData: String? = inputData.getString("input_data")
            Log.e("UploadLogWorker", "doWork()->get inputData:$inputData")
    
            // 任务执行完成后返回数据
            val outputData: Data = Data.Builder().putString("output_data", "Task Success!").build()
            return Result.success(outputData)
        }
    }
    

    新建 CompressLogWorker,表示任务成功运行,代码如下:

    class CompressLogWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
        /**
         * 耗时的任务,在doWork()方法中执行
         *
         * 执行成功返回Result.success()
         * 执行失败返回Result.failure()
         * 需要重新执行返回Result.retry()
         */
        override fun doWork(): Result {
            Log.e("CompressLogWorker", "doWork()")
            return Result.success()
        }
    }
    

    6.1 用 WorkRequest 配置任务的运行时机、方式

    • 设置任务触发条件
      例如当设备充电、已联网、电量充足时,触发任务,代码如下:
            val constraints: Constraints = Constraints.Builder()
                .setRequiresCharging(true)
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .setRequiresBatteryNotLow(true)
                .build()
    
    • 将任务触发条件、延迟执行,指数退避策略、标签,设置到 WorkRequest
            val uploadWorkRequest = OneTimeWorkRequest.Builder(UploadLogWorker::class.java)
                .setConstraints(constraints)//设置触发条件
                .setInitialDelay(10, TimeUnit.SECONDS) // 符合触发条件后,延迟10秒执行
                .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) //设置指数退避算法
                .setInputData(inputData)
                .addTag("UploadTag")
                .build()
    

    通过 WorkManager.getWorkInfosByTag() 可得到 WorkInfo 对象,通过 WorkManager.getWorkInfosByTagLiveData() 可监听任务状态变化,通过 cancelAllWork() 可取消所有任务,

    6.2 一次性、周期性、任务链的 Work

    完整的 MainActivity 代码如下:

    package com.bignerdranch.android.jetpack6workmanagertest
    
    import android.os.Bundle
    import android.util.Log
    import android.widget.Toast
    import androidx.appcompat.app.AppCompatActivity
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            startOneTimeTask()
            // startPeriodicWorkRequest();
            // startChainTask();
        }
    
        // 开启一个一次性任务
        private fun startOneTimeTask() {
            val constraints: Constraints = Constraints.Builder()
                .setRequiresCharging(true)
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .setRequiresBatteryNotLow(true)
                .build()
            val inputData: Data = Data.Builder().putString("input_data", "Hello World!").build()
            val uploadWorkRequest = OneTimeWorkRequest.Builder(UploadLogWorker::class.java)
                .setConstraints(constraints)//设置触发条件
                .setInitialDelay(10, TimeUnit.SECONDS) // 符合触发条件后,延迟10秒执行
                .setBackoffCriteria(BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) //设置指数退避算法
                .setInputData(inputData)
                .addTag("UploadTag")
                .build()
            WorkManager.getInstance(this).enqueue(uploadWorkRequest)
            //实时监听变化
            WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.id).observe(this@MainActivity) { workInfo ->
                Log.d("onChanged()->", "workInfo:$workInfo")
                if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
                    val outputData = workInfo.outputData.getString("output_data")
                    Log.d("onChanged()->", "doWork()->get outputData:$outputData")
                    Toast.makeText(this@MainActivity, "Success!", Toast.LENGTH_LONG).show()
                }
            }
        }
    
        private val TAG = "PeriodicTask"
    
        /**
         * 开启一个定期任务
         *
         * 通过设置TAG的方式来监听任务状态的变化,也可以使用ID的方式来监听
         */
        private fun startPeriodicWorkRequest() {
            val constraints: Constraints = Constraints.Builder()
                .setRequiresCharging(true)
                .build()
    
            //不能少于15分钟
            val uploadWorkRequest = PeriodicWorkRequest.Builder(UploadLogWorker::class.java, 15, TimeUnit.MINUTES)
                .setConstraints(constraints) //设置触发条件
                .addTag(TAG)
                .build()
            WorkManager.getInstance(this).enqueue(uploadWorkRequest)
            WorkManager.getInstance(this).getWorkInfosByTagLiveData(TAG)
                .observe(this@MainActivity) { workInfos -> Log.d("onChanged()->", "workInfo:" + workInfos!![0]) }
        }
    
        /**
         * 取消任务
         */
        private fun cancelAllWork() {
            WorkManager.getInstance(this@MainActivity).cancelAllWork()
        }
    
        /**
         * 开启任务链,任务的执行具有先后顺序
         */
        private fun startChainTask() {
            val constraints: Constraints = Constraints.Builder()
                .setRequiresCharging(true)
                .build()
            val compressWorkRequest = OneTimeWorkRequest.Builder(CompressLogWorker::class.java)
                .setConstraints(constraints) //设置触发条件
                .setInitialDelay(10, TimeUnit.SECONDS) //符合触发条件后,延迟10秒执行
                .build()
            val uploadWorkRequest = OneTimeWorkRequest.Builder(UploadLogWorker::class.java)
                .setConstraints(constraints) //设置触发条件
                .setInitialDelay(10, TimeUnit.SECONDS) //符合触发条件后,延迟10秒执行
                .build()
    
            //实时监听变化
            WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.id)
                .observe(this@MainActivity) { workInfo -> Log.d("onChanged()->", "workInfo:$workInfo") }
        }
    }
    

    运行后,打印日志如下,说明监听到了任务状态的变化:

    2022-09-28 15:54:48.643 11533-11533/com.bignerdranch.android.jetpack6workmanagertest D/onChanged()->: workInfo:WorkInfo{mId='34e59f1e-3bd7-4ec7-9d4c-974dd314e1a9', mState=ENQUEUED, mOutputData=Data {}, mTags=[com.bignerdranch.android.jetpack6workmanagertest.UploadLogWorker, UploadTag], mProgress=Data {}}
    
  • 相关阅读:
    国际版腾讯云阿里云免费开户:全站加快 DCDN 重磅发布!打造新一代加快引擎
    第二十三章《斗地主游戏》第3节:项目完整代码
    EasyPoi导入校验+导入自定义查询等校验
    WOODWARD 5466-318 是否打算转向开放的工业以太网协议
    【Java 错误与异常】微信支付出现 llegal key size 大坑(已解决)
    Protobuf: 高效数据传输的秘密武器
    DPDK 网络加速在 NFV 中的应用
    避坑手册 | JAVA编码中容易踩坑的十大陷阱
    这是什么代码 你能看懂吗
    【Plus】五、常用注解
  • 原文地址:https://blog.csdn.net/jiaoyangwm/article/details/127088443