美文网首页
jetpack-workmanager 使用及源码分析

jetpack-workmanager 使用及源码分析

作者: 付小影子 | 来源:发表于2022-06-13 15:42 被阅读0次

    使用案例

    使用分为三步骤
    1.创建自定义worker,处理后台任务
    2.利用建造者模式 构建WorkRequest(抽象类) 请求,有两个实现类
    OneTimeWorkRequest单次执行任务,执行一次就结束了
    PeriodicWorkRequest 多次循环执行任务
    构建请求的时候,还可以添加约束条件setConstraints(@NonNull Constraints constraints)
    3.WorkManager 把请求加入队列

    自定义worker--简单案例

    class MainWork1(val context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
        //后台任务,并且是 异步放入,线程池执行runnable
        override fun doWork(): Result {
            Log.d("hh", "mainWork1 doWork:run starting...")
            //Toast.makeText(context,"start",Toast.LENGTH_SHORT).show()
            try {
                Thread.sleep(5000)//睡眠
            } catch (e: Exception) {
                e.printStackTrace()
                return Result.failure()
    
            } finally {
                Log.d("hh", "mainWork1 doWork:run ending...")
            }
    
            //failure retry 三种结果
            return Result.success();
    
        }
    }
    

    自定义worker--回传数据

    class MainWork2(val context: Context, val workerParams: WorkerParameters) :
        Worker(context, workerParams) {
        //后台任务,并且是 异步放入,线程池执行runnable
        override fun doWork(): Result {
            Log.d("hh", "mainWork1 doWork:run starting...")
            //Toast.makeText(context,"start",Toast.LENGTH_SHORT).show()
            //获取传递的数据
            val dataString = workerParams.inputData.getString("params")
    
            //回传数据
            val outputData = Data.Builder().putString("name", "付小影子").build()
    
            //Result success(@NonNull Data outputData)
            return Result.success(outputData);
    
        }
    }
    

    调用请求

    class WorkManagerActivity : AppCompatActivity(),
        SharedPreferences.OnSharedPreferenceChangeListener {
        lateinit var sp: SharedPreferences
    
        @RequiresApi(Build.VERSION_CODES.M)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_work_manager)
            //获取sp,并且设置监听
            sp = getSharedPreferences(MainWork6.SP_NAME, MODE_PRIVATE);
            sp.registerOnSharedPreferenceChangeListener(this)
    
    
            /**
             * 简单执行任务
             */
            btn1.setOnClickListener {
                Toast.makeText(this@WorkManagerActivity, "click", Toast.LENGTH_SHORT).show()
                //创建请求 Class<? extends ListenableWorker> workerClass
                val request = OneTimeWorkRequest.Builder(MainWork1::class.java).build()
                //把请求加入队列
                WorkManager.getInstance(this).enqueue(request)
    
            }
    
            /**
             * 回传数据
             */
            btn2.setOnClickListener {
                //构建传递的数据
                val sendData = Data.Builder().putString("params", "123456").build()
                val request =
                    OneTimeWorkRequest.Builder(MainWork2::class.java).setInputData(sendData).build()
    
                //利用状态机(LiveData 只有页面处于活动状态 才会接受数据) 才能接受workManager回馈的数据
                WorkManager.getInstance(this@WorkManagerActivity).getWorkInfoByIdLiveData(request.id)
                    .observe(this@WorkManagerActivity, {
    
                        //enum State ENQUEUED  RUNNING SUCCEEDED FAILED BLOCKED CANCELLED 六种状态
                        Log.d("hh", it.state.name)
    
                        //根据回传的状态,确定数据 Result.success(outputData);
                        // Result failure(@NonNull Data outputData)
                        // (this == SUCCEEDED || this == FAILED || this == CANCELLED)
                        if (it.state.isFinished) {
                            it.outputData.getString("name")?.let { it1 -> Log.d("hh", it1) }
                        }
                    })
                WorkManager.getInstance(this@WorkManagerActivity).enqueue(request)
    
            }
    
            /**
             * 多个任务顺序执行
             */
            btn3.setOnClickListener {
                //顺序执行任务 work3  work4  work5
                val request1 = OneTimeWorkRequest.Builder(MainWork3::class.java).build()
                val request2 = OneTimeWorkRequest.Builder(MainWork4::class.java).build()
                val request3 = OneTimeWorkRequest.Builder(MainWork5::class.java).build()
                //beginWith(@NonNull OneTimeWorkRequest work)
                WorkManager.getInstance(this).beginWith(request1)
                    .then(request2)
                    .then(request3)
                    .enqueue()
    
                //先执行work3,5  最后执行work4
                //beginWith(@NonNull List<OneTimeWorkRequest> work)
                val requestList = listOf<OneTimeWorkRequest>(request1, request3)
                WorkManager.getInstance(this).beginWith(requestList)
                    .then(request2)
                    .enqueue()
    
            }
    
            //重复任务 多次 循环执行,轮循
            btn4.setOnClickListener {
                //OneTimeWorkRequest 是单次执行任务,不会轮循,都继承WorkRequest,抽象类
    
                //重复的,多次的,循环的任务
                //为了省电优化,设置的默认时间是15分钟。所以即使我们配置为10s 执行一次后台任务,也会是15分钟执行
                val request =
                    PeriodicWorkRequest.Builder(MainWork3::class.java, 10, TimeUnit.SECONDS).build()
    
                //因为是多次轮循,所以一直都拿不到success结果,不出错不取消的情况下,一直是 ENQUEUED  RUNNING来回切换
                WorkManager.getInstance(this).getWorkInfoByIdLiveData(request.id)
                    .observe(this, {
                        Log.d("hh", it.state.name) //不出错不取消的情况下,一直是 ENQUEUED  RUNNING来回切换
                        if (it.state.isFinished) {
                            Log.d("hh", "任务执行结束....")
                        }
                    })
                //加入队列
                WorkManager.getInstance(this).enqueue(request)
                //取消任务,只是表面的取消,任务还是得执行完成 cancelWorkById(request.id) cancelAllWork() cancelAllWorkByTag()
                //WorkManager.getInstance(this).cancelWorkById(request.id)
            }
    
            /**
             * 添加约束条件,执行后台任务
             */
            btn5.setOnClickListener {
                //定义约束条件
                val constrains = Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED) //必须是联网状态
                    .setRequiresCharging(true)//添加 充电中状态
                    .setRequiresDeviceIdle(true)//添加闲时状态
                    .setRequiresBatteryNotLow(true)//不是低电量状态
                    .build()
    
                //创建请求,绑定约束条件
                val request =
                    OneTimeWorkRequest.Builder(MainWork3::class.java).setConstraints(constrains).build()
    
                //加入队列
                WorkManager.getInstance(this).enqueue(request)
            }
    
            /**
             * 测试 任务一直在后台运行。。利用sp写入数据,刷新到页面上
             */
            btn6.setOnClickListener {
                //定义约束条件
                val constrains = Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED) //必须是联网状态
                    .build()
    
                //创建请求,绑定约束条件
                val request =
                    OneTimeWorkRequest.Builder(MainWork6::class.java).setConstraints(constrains).build()
    
                //加入队列
                WorkManager.getInstance(this).enqueue(request)
    
            }
        }
    
        //当sp 文件内容被改变时候,会回调此函数
        override fun onSharedPreferenceChanged(p0: SharedPreferences?, p1: String?) {
            tvValue.text = "后台任务数据--${sp.getInt(MainWork6.SP_KEY, 0)}"
        }
    }
    

    常见面试提问

    workmanager 是干嘛用的?

    处理非及时任务的,比如每天同步一次数据到服务器,这种类似的需求,不是及时执行,但是又保证一定会被执行的非及时任务。

    workmanager 是怎么保证,把APP退出后,还能正常运行?

    记录用户的所有任务信息,并且保存的数据库中,没有保存在内存中,就是为了持久性保存记录。所有APP被杀掉后,依然可以获取所以的任务信息。然后通过广播和系统级别的服务(SystemAlertService),进行任务执行。

    workmanager 任务是怎么保证一定会执行的?

    Android 操作系统会在系统级别的服务中,来判断用户的约束条件,当约束条件满足时,就会执行任务,但是触发检测是采用广播的形式处理的,比如网络连接成功就触发等。

    源码解析

    workmanager注入说明

    打包apk的时候,Android 系统会在配置清单文件中生成ContentProver作为workmanager的入口配置,执行第一次初始化。利用系统级别service,即使APP退出后台,仍旧能保证任务的执行。


    111.png

    源代码代码执行流程

    222.png 333.png 444.png

    广播执行的流程

    添加的约束条件,会生成很多广播,这些广播只是个空壳子,并没有实现操作。创建了个总广播,来处理各种广播receive。


    555.png

    相关文章

      网友评论

          本文标题:jetpack-workmanager 使用及源码分析

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