跳到主要内容

WorkManager

问题

WorkManager 是什么?它和其他后台任务方案有什么区别?

答案

核心概念

WorkManager 是 Jetpack 中用于可靠执行后台任务的 API。特点是:

  • 保证执行:即使应用退出或设备重启,任务仍会执行
  • 约束条件:可设置网络、电量、存储等前提条件
  • 向后兼容:内部根据 API 级别选用 JobScheduler 或 AlarmManager

适用场景

方案适用场景
协程需要立即执行,app 在前台
AlarmManager精确定时(闹钟)
WorkManager可延迟、需要保证执行(上传日志、同步数据)

基本使用

// 1. 定义 Worker
class UploadWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {

override suspend fun doWork(): Result {
val imageUri = inputData.getString("image_uri") ?: return Result.failure()

return try {
uploadImage(imageUri)
Result.success() // 成功
} catch (e: Exception) {
if (runAttemptCount < 3) {
Result.retry() // 失败重试
} else {
Result.failure() // 最终失败
}
}
}
}

// 2. 构建请求
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setInputData(workDataOf("image_uri" to uri.toString()))
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // 需要网络
.setRequiresBatteryNotLow(true) // 电量不低
.build()
)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL, // 指数退避
10, TimeUnit.SECONDS
)
.addTag("upload")
.build()

// 3. 提交
WorkManager.getInstance(context).enqueue(uploadRequest)

任务链

WorkManager.getInstance(context)
.beginWith(listOf(downloadWork1, downloadWork2)) // 并行
.then(processWork) // 串行
.then(uploadWork) // 串行
.enqueue()

周期任务

val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
repeatInterval = 1, TimeUnit.HOURS, // 最短 15 分钟
flexInterval = 15, TimeUnit.MINUTES // 在周期末尾的弹性窗口内执行
).build()

WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
"sync",
ExistingPeriodicWorkPolicy.KEEP, // 已存在则保留
syncRequest
)

观察任务状态

WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this) { info ->
when (info.state) {
WorkInfo.State.RUNNING -> showProgress()
WorkInfo.State.SUCCEEDED -> showSuccess()
WorkInfo.State.FAILED -> showError()
else -> {}
}
}

常见面试问题

Q1: WorkManager 的内部实现原理?

答案

  1. 任务信息存储在内部 Room 数据库中(保证重启后可恢复)
  2. 根据 API 级别选择执行后端:
    • API >= 23:JobScheduler
    • API < 23:AlarmManager + BroadcastReceiver
  3. 约束条件通过系统回调或 ContentObserver 监听,满足后触发执行

Q2: WorkerCoroutineWorker 的区别?

答案

  • WorkerdoWork() 在后台线程同步阻塞执行
  • CoroutineWorkerdoWork()suspend 函数,可使用协程,默认在 Dispatchers.Default 上运行

推荐使用 CoroutineWorker

Q3: 如何确保唯一任务不重复?

答案

WorkManager.getInstance(context).enqueueUniqueWork(
"unique_sync",
ExistingWorkPolicy.REPLACE, // KEEP / REPLACE / APPEND
syncRequest
)
  • KEEP:如果已有同名任务,忽略新请求
  • REPLACE:取消旧任务,提交新任务
  • APPEND:排队,旧任务完成后再执行

相关链接