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。
在app目录下的build.gradle导入依赖库
// 导入WorkManager依赖
def work_version = "2.3.4"
implementation "androidx.work:work-runtime:$work_version"
布局文件 activity_main.xml
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)
}
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)
}
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()
}
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);
}
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)
}
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) // 执行流程源码分析
}
}