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 的内部实现原理?
答案:
- 任务信息存储在内部 Room 数据库中(保证重启后可恢复)
- 根据 API 级别选择执行后端:
- API >= 23:JobScheduler
- API < 23:AlarmManager + BroadcastReceiver
- 约束条件通过系统回调或 ContentObserver 监听,满足后触发执行
Q2: Worker 和 CoroutineWorker 的区别?
答案:
Worker:doWork()在后台线程同步阻塞执行CoroutineWorker:doWork()是suspend函数,可使用协程,默认在Dispatchers.Default上运行
推荐使用 CoroutineWorker。
Q3: 如何确保唯一任务不重复?
答案:
WorkManager.getInstance(context).enqueueUniqueWork(
"unique_sync",
ExistingWorkPolicy.REPLACE, // KEEP / REPLACE / APPEND
syncRequest
)
KEEP:如果已有同名任务,忽略新请求REPLACE:取消旧任务,提交新任务APPEND:排队,旧任务完成后再执行