Android 背景任務專家
專精於 Android 背景執行,涵蓋 WorkManager、前景服務、低電耗模式處理與電池高效處理。
觸發條件
啟用於: "WorkManager"、"Android 背景任務"、"前景服務"、"低電耗模式"、"電池最佳化"、"定期工作"、"背景同步"、"JobScheduler"、"Android 背景處理"
不適用於: iOS 背景任務 → swiftui-data-flow-expert | React Native 背景任務 → mobile-offline-sync-architect | UI 架構 → jetpack-compose-navigation-expert
快速入門
- 選擇正確的 API — 可延遲工作使用 WorkManager,使用者可見的持續性任務使用前景服務,短暫非同步工作使用協程
- 定義工作者 — 繼承
CoroutineWorker並使用暫停函數來實現簡潔的非同步程式碼 - 設定限制條件 — 網路類型、電量、儲存空間需求
- 處理低電耗模式與 App 待機 — 使用 WorkManager(而非 AlarmManager)進行相容於低電耗模式的排程
- 透過 adb 進行測試 — 強制進入低電耗模式,並驗證工作是否在滿足限制條件時執行
核心能力
| 領域 | 技術 |
|---|---|
| 可延遲工作 | WorkManager 2.10, OneTimeWorkRequest, PeriodicWorkRequest |
| 前景執行 | 前景服務類型 (dataSync, location, mediaPlayback, shortService) |
| 限制條件 | NetworkType, BatteryNotLow, StorageNotLow, DeviceIdle |
| 工作鏈 | WorkContinuation, 平行鏈, 唯一工作策略 |
| 測試 | 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 的鬧鐘不相容於低電耗模式且耗電。請改用尊重低電耗模式、App 待機與省電模式的 WorkManager。
- 沒有前景通知的背景服務 — Android 12+ 會終止背景服務。請使用前景服務並正確宣告類型,或使用 WorkManager。
- 定期工作間隔低於 15 分鐘 — WorkManager 強制要求最小間隔為 15 分鐘。若需要更頻繁的工作,請使用前景服務或具備生命週期感知能力的協程。
- 未宣告前景服務類型 — Android 14+ 要求在 Manifest 中明確宣告
foregroundServiceType。省略會導致SecurityException。 - 忽略工作觀察 — 啟動工作卻未向使用者顯示進度。請透過
getWorkInfoByIdLiveData()或getWorkInfoByIdFlow()觀察WorkInfo以更新 UI。
品質檢查清單
[ ] 使用 WorkManager 處理可延遲背景任務(非 AlarmManager)
[ ] 在 AndroidManifest 中以正確類型宣告前景服務
[ ] 已設定限制條件(網路、電量、儲存空間)
[ ] 針對暫時性失敗設定含退避策略的重試機制
[ ] 為定期/一次性工作設定唯一工作策略
[ ] 工作進度可從 UI 觀察
[ ] 已透過 adb 測試低電耗模式:`adb shell dumpsys deviceidle force-idle`
[ ] 已測試電池最佳化:`adb shell am set-inactive <package> true`
[ ] 已使用 TestWorkerBuilder 測試工作者
[ ] 已為前景服務通知建立通知頻道
[ ] 工作鏈能妥善處理部分失敗情況
[ ] 背景工作尊重使用者的省電模式偏好