Android 后台任务专家 是做什么的?
精通 Android 后台执行,涵盖 WorkManager、前台服务、Doze 模式处理以及电池高效处理。
激活触发器
在以下情况激活: "WorkManager", "background task Android", "Foreground Service", "Doze mode", "battery optimization", "periodic work", "background sync", "JobScheduler", "background processing Android"
不适用于: iOS 后台任务 → swiftui-data-flow-expert | React Native 后台任务 → mobile-offline-sync-architect | UI 架构 → jetpack-compose-navigation-expert
快速开始
- 选择正确的 API — 可推迟工作使用 WorkManager,用户可见的持续任务使用前台服务,短时异步工作使用协程
- 定义 Worker — 继承
CoroutineWorker并使用挂起函数实现简洁的异步代码 - 配置约束 — 网络类型、电池电量、存储空间要求
- 处理 Doze 和 App Standby — 使用 WorkManager(而非 AlarmManager)进行 Doze 兼容调度
- 使用 adb 测试 — 强制进入 Doze 模式并验证工作是否在满足约束时执行
核心能力
| 领域 | 技术 |
|---|---|
| 可推迟工作 | WorkManager 2.10, OneTimeWorkRequest, PeriodicWorkRequest |
| 前台 | 前台服务类型 (dataSync, location, mediaPlayback, shortService) |
| 约束 | NetworkType, BatteryNotLow, StorageNotLow, DeviceIdle |
| 链式任务 | WorkContinuation, parallel chains, unique work policies |
| 测试 | TestWorkerBuilder, TestListenableWorkerBuilder, WorkManagerTestInitHelper |
架构模式
WorkManager 决策树
任务是由用户发起且需要完成吗?
├─ 是 → 是短任务(< 10 分钟)吗?
│ ├─ 是 → 前台服务(shortService 类型)
│ └─ 否 → 前台服务(dataSync, location 等)
│
└─ 否 → 是否可以推迟?
├─ 是 → WorkManager
│ ├─ 一次性的? → OneTimeWorkRequest
│ └─ 周期性的? → PeriodicWorkRequest(最小间隔 15 分钟)
│
└─ 否 → 应用在前台可见时执行?
├─ 是 → CoroutineScope (viewModelScope 或 lifecycleScope)
└─ 否 → 你可能还是需要使用 WorkManager
带有重试和进度的 CoroutineWorker
@HiltWorker
class SyncWorker @AssistedInject constructor(
@Assisted context: Context,
@Assisted params: WorkerParameters,
private val syncRepository: SyncRepository,
private val notificationHelper: NotificationHelper,
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// 报告进度供 UI 观察
setProgress(workDataOf("progress" to 0))
return try {
val pendingItems = syncRepository.getPendingChanges()
pendingItems.forEachIndexed { index, item ->
syncRepository.syncItem(item)
setProgress(workDataOf(
"progress" to ((index + 1) * 100 / pendingItems.size)
))
}
Result.success(workDataOf("synced" to pendingItems.size))
} catch (e: IOException) {
if (runAttemptCount < 3) {
Result.retry() // 默认指数退避
} else {
Result.failure(workDataOf("error" to e.message))
}
}
}
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID,
notificationHelper.createSyncNotification()
)
}
}
带约束和链式任务的调度
// 每 1 小时(最小 15 分钟)调度一次周期性同步
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(1, TimeUnit.HOURS)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
WorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS
)
.addTag("sync")
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"periodic-sync",
ExistingPeriodicWorkPolicy.KEEP, // 如果已调度则不重新启动
syncRequest
)
// 链式任务:下载 → 处理 → 上传(顺序执行)
WorkManager.getInstance(context)
.beginWith(downloadWork)
.then(processWork)
.then(uploadWork)
.enqueue()
反模式
- 对可推迟工作使用 AlarmManager — AlarmManager 的闹钟不兼容 Doze 模式且消耗电池。请使用 WorkManager,它会尊重 Doze、App Standby 和电池节省模式。
- 没有前台通知的后台服务 — Android 12+ 会杀死后台服务。请使用带有正确类型声明的前台服务或 WorkManager。
- 间隔小于 15 分钟的 PeriodicWork — WorkManager 强制要求最小间隔为 15 分钟。如需更频繁的工作,请使用前台服务或具有生命周期感知的协程。
- 未声明前台服务类型 — Android 14+ 要求在 Manifest 中明确声明
foregroundServiceType。省略会导致SecurityException。 - 忽略工作观察 — 启动工作但不向用户显示进度。通过
getWorkInfoByIdLiveData()或getWorkInfoByIdFlow()观察WorkInfo来更新 UI。
质量检查清单
[ ] 使用 WorkManager 处理可推迟的后台任务(非 AlarmManager)
[ ] 在 AndroidManifest 中声明了正确的 Foreground Service 类型
[ ] 配置了约束(网络、电池、存储)
[ ] 为临时故障设置了带退避的重试策略
[ ] 为周期性/一次性工作设置了唯一工作策略
[ ] 工作进度可从 UI 观察
[ ] 通过 adb 测试了 Doze 模式:`adb shell dumpsys deviceidle force-idle`
[ ] 测试了电池优化:`adb shell am set-inactive <package> true`
[ ] 使用 TestWorkerBuilder 测试了 Worker
[ ] 为前台服务通知创建了通知渠道
[ ] 工作链优雅地处理了部分失败
[ ] 后台工作尊重用户的电池节省器偏好