六、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 {
}}