WorkManager的基本使用

目录

  • 一、WorkManager概述
    • 1. WorkManager的作用:
    • 2. WorkManager的各个角色
  • 二、依赖库的导入
  • 三、WorkManager几种基本使用
    • 1. 单一任务的执行
    • 2. 数据 互相传递
    • 3. 多个任务 顺序执行
    • 4. 重复执行后台任务
    • 5. 约束条件
    • 6. 证明 app被杀掉之后,还在后台执行
  • 四、WorkManager源码流程图

一、WorkManager概述

WorkManage: 排队和管理工作请求;将WorkRequest对象传递WorkManager的任务队列

(注意:如果未指定任何约束,WorkManager立即运行任务)

WorkStatus: 包含有关特点任务的信息;可以使用LiveData保存WorkStatus对象,监听任务状态;如LiveData

  你的任务不可能总是在前台,但是还要确保你的那么重要任务执行,就可以放置在后台执行,那么WorkManager就发挥其作用了。
  WorkManager是Android Jetpack提供执行后台任务管理的组件,它适用于需要保证系统即使应用程序退出也会运行的任务,WorkManager API可以轻松指定可延迟的异步任务以及何时运行它们,这些API允许您创建任务并将其交给WorkManager立即允许或在适当的时间运行。
  WorkManager根据设备API级别和应用程序状态等因素选择适当的方式来运行任务。如果WorkManager在应用程序运行时执行您的任务之一,WorkManager可以在您应用程序进程的新进程钟运行您的任务。如果您的应用程序未运行,WorkManager会选择一种合适的方式来安排后台任务–具体取决于设备API级别和包含的依赖项,WorkManager可能会使用JobScheduler,Firebase JobDispatcher或AlarmManager。

1. WorkManager的作用:

    1. 确保重要的后台任务,一定会被执行,后台任务(例如:非及时性的(请求服务器 及时性)上传、下载 ,同步数据等)
    1. 内部对电量进行了优化,不需要我们去处理电量优化了
    1. API 14 到最新版本,都可以使用WorkManager来管理你的后台任务
    1. 注意:WorkManager不能做保活操作
    1. 调度,管理,执行的后台任务的场景,通常是可延迟的后台任务

2. WorkManager的各个角色

  1. Worker:可以这样理解,指定需要执行的任务,可以成为Worker类的之类,在实现的方法钟,就可以执行任务逻辑了。
  2. WorkRequest:可以这样理解,执行一项单一的任务
    • 第一点:必须知道WorkRequest对象必须指定Work执行的任务
    • 第二点:需要知道WorkRequest都有一个自动生成的唯一ID,可以使用ID执行取消排队任务 或 获取任务状态等操作
    • 第三点:需要知道WorkRequest是一个抽象的类;系统默认实现子类OneTimeWorkRequest 或 PeriodicWorkRequest
    • 第四点:需要知道WorkRequest.Builder创建WorkRequest对象;相应的子类:OneTimeWorkRequest.Builder 或 PeriodicWorkRequest.Builder
    • 第五点:需要知道Constraints:指定对任务运行时间的限制(任务约束);使用Constraints.Builder创建Constraints对象,并传递给WorkRequest.Builder

二、依赖库的导入

在app目录下的build.gradle导入依赖库

// 导入WorkManager依赖
def work_version = "2.3.4"
implementation "androidx.work:work-runtime:$work_version"

三、WorkManager几种基本使用

布局文件 activity_main.xml




    

1. 单一任务的执行

MainWorker1.kt

package com.example.myworkmanager

import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

// 最简单的执行任务
class MainWorker1(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {

    // 定义静态变量  相对于java static   const val相对于定义常量
    companion object { const val TAG = "abc" }

    // 后台任务 并且 异步的(原理:线程池执行Runnable)
    override fun doWork(): Result {
        Log.d(TAG, "MainWorker1 doWork: run started ...")
        try {
            Thread.sleep(3000)  // 睡眠
        } catch (e : InterruptedException) {
            e.printStackTrace()
            Result.failure()  // 本次任务失败
        } finally {
            Log.d(TAG, "MainWorker1 doWork: run end ...")
        }

        return Result.success()  // 本次任务完成
    }
}

MainActivity.kt

 /**
  * 最简单的 执行任务
  * 测试后台任务1
  */
 fun testBackgroundWork1(view: View) {

     // OneTimeWorkRequest 单个 一次的任务
     val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker1::class.java).build()

     WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)

 }

2. 数据 互相传递

MainWorker2.kt

package com.example.myworkmanager

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Data
import androidx.work.Worker
import androidx.work.WorkerParameters

class MainWorker2(context: Context, private val workerParameters: WorkerParameters) : Worker(context, workerParameters) {

    companion object {
        const val TAG = "abc"
    }

    // 后台任何 并且异步的(原理:线程池执行Runnable)
    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {
        Log.d(TAG, "MainWorker2 dowork: 后台任务执行了")

        // 接收MainActivity传递过来的数据
        val dataString = workerParameters.inputData.getString("maiworker2")
        Log.d(TAG, "MainWorker2 dowork: 接收MainActivity传递过来的数据:$dataString")

        // 反馈数据给MainActivity
        // 把任务中的数据回传到MainActivity中
        val outputData = Data.Builder().putString("mainworker2", "mainworker2回传的数据").build()

        /*
        return Result.Failure()  // 本次执行 doWork任务时 失败
        return Result.Retry()    // 本次执行 doWork任务时 重试一次
        return Result.Success()  // 本次执行 doWork任务时 成功 执行任务完毕
        */
        return Result.Success(outputData);
    }
}

MainActivity.kt

    /**
     * 数据 互相传递
     * 测试后台任务2
     * 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED
     */
    fun testBackgroundWork2(view: View) {
        // 单一、一次的任务
        val oneTimeWorkRequest : OneTimeWorkRequest

        // 数据
        val sendData = Data.Builder().putString("mainworker2", "传给mainworker2的数据").build()

        // 请求对象初始化
        oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker2::class.java)
            .setInputData(sendData) // 数据的携带 发送 一般都是 携带到Request里面去 发送数据给WorkManager2
            .build()

        // 一般都是通过 状态机 接收 WorkManager2的回馈数据
        // 状态机(LiveData)才能接收 WorkManager 回馈的数据
        WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
            .observe(this, Observer{ workInfo ->

                // 状态包含:ENQUEUED、RUNNING、SUCCEEDED
                Log.d(MainWorker2.TAG, "状态:" + workInfo.state.name);

                // ENQUEUED, RUNNING 都取不到 回馈的数据,都是null
                // Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))

                if (workInfo.state.isFinished) {  // 判断成功 SUCCEEDED状态
                    Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))
                }
            })
        WorkManager.getInstance(this).equals(oneTimeWorkRequest)
    }

3. 多个任务 顺序执行

MainWorker3.kt

package com.example.myworkmanager

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class MainWorker3(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){

    companion object { const val TAG = "abc" }

    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {
        Log.d(TAG, "MainWorker3 doWork: 后台任务执行了")
        return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕
    }
}

MainWorker4.kt

package com.example.myworkmanager

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class MainWorker4(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){

    companion object { const val TAG = "abc" }

    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {
        Log.d(TAG, "MainWorker4 doWork: 后台任务执行了")
        return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕
    }
}

MainWorker5.kt

package com.example.myworkmanager

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class MainWorker5(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){

    companion object { const val TAG = "abc" }

    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {
        Log.d(TAG, "MainWorker5 doWork: 后台任务执行了")
        return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕
    }
}

MainWorker6.kt

package com.example.myworkmanager

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class MainWorker6(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){

    companion object { const val TAG = "abc" }

    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {
        Log.d(TAG, "MainWorker3 doWork: 后台任务执行了")
        return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕
    }
}

MainActivity.kt

/**
     * 多个任务  顺序执行
     * 测试后台任务3
     */
    fun testBackgroundWork3(view: View) {
        // 单一、一次的任务
        val oneTimeWorkRequest3 = OneTimeWorkRequest.Builder(MainWorker3::class.java).build()
        val oneTimeWorkRequest4 = OneTimeWorkRequest.Builder(MainWorker4::class.java).build()
        val oneTimeWorkRequest5 = OneTimeWorkRequest.Builder(MainWorker5::class.java).build()
        val oneTimeWorkRequest6 = OneTimeWorkRequest.Builder(MainWorker6::class.java).build()

        // 顺序执行 3 4 5 6
        WorkManager.getInstance(this)
            .beginWith(oneTimeWorkRequest3)
            .then(oneTimeWorkRequest4)
            .then(oneTimeWorkRequest5)
            .then(oneTimeWorkRequest6)
            .enqueue()

        // 另外一种使用
        // 需求: 先执行3 4 最后执行6
        val oneTimeWorkRequests : MutableList = ArrayList()   // 集合方式
        oneTimeWorkRequests.add(oneTimeWorkRequest3)
        oneTimeWorkRequests.add(oneTimeWorkRequest4)

        WorkManager.getInstance(this)
            .beginWith(oneTimeWorkRequests)
            .then(oneTimeWorkRequest6)
            .enqueue()
    }

4. 重复执行后台任务

MainActivity.kt

    /**
     * 重复执行后台任务 非单个任务 ,多个任务
     * 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED
     */
    fun testBackgroundWork4(view: View) {
        // OneTimeWorkRequest 单个任务  不会轮询  执行一次就结束

        // 重复的任务  多次/循环/轮询 哪怕设置为10s轮询一次,那么最少轮询/循环一次 也要15分钟(google规定)
        // 不能小于15分钟,否则默认修改成15分钟
        val periodicWorkRequest = PeriodicWorkRequest.Builder(MainWorker3::class.java,10, TimeUnit.SECONDS).build()

        // 状态机 为什么一直都是ENQUEUED 和 RUNNING,因为 你是轮询的任务,SUCCEEDED
        // 如果是单个任务,就会看到SUCCEEDED结束任务
        // 监听状态
        WorkManager.getInstance(this)
            .getWorkInfoByIdLiveData(periodicWorkRequest.id)
            .observe(this, Observer {workInfo ->
                Log.d("abc", "状态:" + workInfo.state.name)  // ENQUEUED RUNNING  循环反复

                if(workInfo.state.isFinished) {
                    Log.d("abc", "状态:isFinished = true 注意:后台任务已经完成了...")
                }
            })
         WorkManager.getInstance(this).equals(periodicWorkRequest)
        
        // 取消 任务的执行
        //WorkManager.getInstance(this).cancelWorkById(periodicWorkRequest.id);
    }

5. 约束条件

MainActivity.kt

/**
     * 约束条件,约束后台任务执行
     * 测试后台任务5
     */
    fun testBackgroundWork5(view: View) {
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)  // 必须是联网中
            .setRequiresCharging(true)    // 必须是充当中
            .setRequiresDeviceIdle(true)  // 必须是空闲时
            .build()
        /**
         * 除了上面设置的约束外,WorkManager还提供了以下的约束作为Work执行的条件:
         * setRequiredNetworkType:网络连接设置
         * setRequiresBatteryNotLow:是否为低电量时运行,默认false
         * setRequiresCharging:是否要插入设备(接入电源),默认false
         * setRequiresDeviceIdle:设备是否空闲,默认false
         * setRequiresStorageNotLow:设备可用存储是否不低于临界阈值
         */

        // 请求对象
        val request = OneTimeWorkRequest.Builder(MainWorker3::class.java)
            .setConstraints(constraints)
            .build()

        // 加入队列
        WorkManager.getInstance(this).enqueue(request)
    }

6. 证明 app被杀掉之后,还在后台执行

MainActivity.kt

class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
/**
     * 证明 app被杀掉之后,还在后台执行,通过写入文件的方式(SP)
     * 测试后台任务6
     */
    fun testBackgroundWork6(view: View) {
        // 约束条件
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)  // 约束条件 必须是网络连接
            .build()

        // 构建Request
        val request = OneTimeWorkRequest.Builder(MainWorker7::class.java)
            .setConstraints(constraints)
            .build()

        // 加入队列
        WorkManager.getInstance(this).enqueue(request)

    }

    // SP归零
    fun spReset(view: View) {
        val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)
        sp.edit().putInt(MainWorker7.SP_KEY, 0).apply()
        updateToUI()
    }

    // 从SP里面获取值,显示到界面给用户看
    private fun updateToUI() {
        val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)
        val resultValue = sp.getInt(MainWorker7.SP_KEY, 0)
        bt6?.text = "测试后台任务6---$resultValue"

    }

    // 文件内容只要有变化,此函数就会执行
    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) = updateToUI()

}

MainActivity.kt 完整代码:

package com.example.myworkmanager

import android.content.Context
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.lifecycle.Observer
import androidx.work.*
import kotlinx.android.synthetic.main.activity_main.*
import java.util.concurrent.TimeUnit

class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    /**
     * 最简单的 执行任务
     * 测试后台任务1
     */
    fun testBackgroundWork1(view: View) {

        // OneTimeWorkRequest 单个 一次的任务
        val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker1::class.java).build()

        WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)

    }

    /**
     * 数据 互相传递
     * 测试后台任务2
     * 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED
     */
    fun testBackgroundWork2(view: View) {
        // 单一、一次的任务
        val oneTimeWorkRequest : OneTimeWorkRequest

        // 数据
        val sendData = Data.Builder().putString("mainworker2", "传给mainworker2的数据").build()

        // 请求对象初始化
        oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker2::class.java)
            .setInputData(sendData) // 数据的携带 发送 一般都是 携带到Request里面去 发送数据给WorkManager2
            .build()

        // 一般都是通过 状态机 接收 WorkManager2的回馈数据
        // 状态机(LiveData)才能接收 WorkManager 回馈的数据
        WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
            .observe(this, Observer{ workInfo ->

                // 状态包含:ENQUEUED、RUNNING、SUCCEEDED
                Log.d(MainWorker2.TAG, "状态:" + workInfo.state.name);

                // ENQUEUED, RUNNING 都取不到 回馈的数据,都是null
                // Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))

                if (workInfo.state.isFinished) {  // 判断成功 SUCCEEDED状态
                    Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))
                }
            })
        WorkManager.getInstance(this).equals(oneTimeWorkRequest)
    }

    /**
     * 多个任务  顺序执行
     * 测试后台任务3
     */
    fun testBackgroundWork3(view: View) {
        // 单一、一次的任务
        val oneTimeWorkRequest3 = OneTimeWorkRequest.Builder(MainWorker3::class.java).build()
        val oneTimeWorkRequest4 = OneTimeWorkRequest.Builder(MainWorker4::class.java).build()
        val oneTimeWorkRequest5 = OneTimeWorkRequest.Builder(MainWorker5::class.java).build()
        val oneTimeWorkRequest6 = OneTimeWorkRequest.Builder(MainWorker6::class.java).build()

        // 顺序执行 3 4 5 6
        WorkManager.getInstance(this)
            .beginWith(oneTimeWorkRequest3)
            .then(oneTimeWorkRequest4)
            .then(oneTimeWorkRequest5)
            .then(oneTimeWorkRequest6)
            .enqueue()

        // 另外一种使用
        // 需求: 先执行3 4 最后执行6
        val oneTimeWorkRequests : MutableList = ArrayList()   // 集合方式
        oneTimeWorkRequests.add(oneTimeWorkRequest3)
        oneTimeWorkRequests.add(oneTimeWorkRequest4)

        WorkManager.getInstance(this)
            .beginWith(oneTimeWorkRequests)
            .then(oneTimeWorkRequest6)
            .enqueue()
    }

    /**
     * 重复执行后台任务 非单个任务 ,多个任务
     * 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED
     */
    fun testBackgroundWork4(view: View) {
        // OneTimeWorkRequest 单个任务  不会轮询  执行一次就结束

        // 重复的任务  多次/循环/轮询 哪怕设置为10s轮询一次,那么最少轮询/循环一次 也要15分钟(google规定)
        // 不能小于15分钟,否则默认修改成15分钟
        val periodicWorkRequest = PeriodicWorkRequest.Builder(MainWorker3::class.java,10, TimeUnit.SECONDS).build()

        // 状态机 为什么一直都是ENQUEUED 和 RUNNING,因为 你是轮询的任务,SUCCEEDED
        // 如果是单个任务,就会看到SUCCEEDED结束任务
        // 监听状态
        WorkManager.getInstance(this)
            .getWorkInfoByIdLiveData(periodicWorkRequest.id)
            .observe(this, Observer {workInfo ->
                Log.d("abc", "状态:" + workInfo.state.name)  // ENQUEUED RUNNING  循环反复

                if(workInfo.state.isFinished) {
                    Log.d("abc", "状态:isFinished = true 注意:后台任务已经完成了...")
                }
            })
        WorkManager.getInstance(this).equals(periodicWorkRequest)
        
        // 取消 任务的执行
        //WorkManager.getInstance(this).cancelWorkById(periodicWorkRequest.id);
    }

    /**
     * 约束条件,约束后台任务执行
     * 测试后台任务5
     */
    fun testBackgroundWork5(view: View) {
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)  // 必须是联网中
            .setRequiresCharging(true)    // 必须是充当中
            .setRequiresDeviceIdle(true)  // 必须是空闲时
            .build()
        /**
         * 除了上面设置的约束外,WorkManager还提供了以下的约束作为Work执行的条件:
         * setRequiredNetworkType:网络连接设置
         * setRequiresBatteryNotLow:是否为低电量时运行,默认false
         * setRequiresCharging:是否要插入设备(接入电源),默认false
         * setRequiresDeviceIdle:设备是否空闲,默认false
         * setRequiresStorageNotLow:设备可用存储是否不低于临界阈值
         */

        // 请求对象
        val request = OneTimeWorkRequest.Builder(MainWorker3::class.java)
            .setConstraints(constraints)
            .build()

        // 加入队列
        WorkManager.getInstance(this).enqueue(request)
    }

    /**
     * 证明 app被杀掉之后,还在后台执行,通过写入文件的方式(SP)
     * 测试后台任务6
     */
    fun testBackgroundWork6(view: View) {
        // 约束条件
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)  // 约束条件 必须是网络连接
            .build()

        // 构建Request
        val request = OneTimeWorkRequest.Builder(MainWorker7::class.java)
            .setConstraints(constraints)
            .build()

        // 加入队列
        WorkManager.getInstance(this).enqueue(request)

    }

    // SP归零
    fun spReset(view: View) {
        val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)
        sp.edit().putInt(MainWorker7.SP_KEY, 0).apply()
        updateToUI()
    }

    // 从SP里面获取值,显示到界面给用户看
    private fun updateToUI() {
        val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)
        val resultValue = sp.getInt(MainWorker7.SP_KEY, 0)
        bt6?.text = "测试后台任务6---$resultValue"

    }

    // 文件内容只要有变化,此函数就会执行
    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) = updateToUI()


    // TODO ------------------------下面是源码分析环节

    /**
     * TODO 分析源码
     */
    fun codeStudy(view: View) {
        // 没有约束条件

        // 请求对象
        val request = OneTimeWorkRequest.Builder(MainWorker3::class.java).build()

        // 第一次初始化是在 ContentProvider
        /**
         * APK 清单文件里面(第一次初始化)执行
         * 成果 WorkManagerImpl构建出来了
         * 1. 初始化 数据库 ROOM 来保存你的任务(持久性保存的)手机重启 APP被杀掉  没关系 一定执行
         * 2. 初始化 埋下伏笔 new GreedyScheduler(context, taskExcutor, this)
         * 3. 初始化 配置信息 configuration (执行信息  线程池任务)
         */

        WorkManager.getInstance(this) // 这里已经是第二次初始化了
            .enqueue(request)  // 执行流程源码分析

    }


}

四、WorkManager源码流程图

WorkManager的基本使用_第1张图片

你可能感兴趣的:(kotlin,WorkManager,jetpack)