Android WorkManager 背景任務處理

在 Android 開發中,處理背景任務有許多選擇(如 Coroutines, Services),但當你需要執行「即使 App 關閉或裝置重啟也要保證執行」且「可延遲執行」的任務時,WorkManager 是唯一的標準解答。

核心概念與優勢

WorkManager 並不是另一種執行緒方案,它是系統層級的任務排程器:

  • 持久性 (Persistence):任務資訊存於資料庫,手機重啟後仍會繼續執行。
  • 條件約束 (Constraints):可以設定「充電時」、「有網路」或「空間足夠」時才執行。
  • 適配性:自動根據 API Level 選擇底層實作(JobScheduler 或 AlarmManager)。

定位與實作 Worker

我們建議使用 CoroutineWorker,它能讓你以非同步且非阻塞的方式撰寫背景邏輯。

定位 Worker

class ImageUploadWorker(
    appContext: Context,
    params: WorkerParameters
) : CoroutineWorker(appContext, params) {

    override suspend fun doWork(): Result {
        // 接收傳入的參數
        val imageUri = inputData.getString("IMAGE_URI") ?: return Result.failure()

        return try {
            // 執行耗時工作 (如上傳)
            val outputUrl = uploadImage(imageUri)
            
            // 回傳成功並帶回結果
            val outputData = workDataOf("URL" to outputUrl)
            Result.success(outputData)
        } catch (e: Exception) {
            // 判斷是否需要自動重試
            if (runAttemptCount < 3) Result.retry() else Result.failure()
        }
    }
}

提交任務請求 (WorkRequest)

加入條件與重試策略

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.UNMETERED) // 僅限 WiFi
    .setRequiresCharging(true) // 必須在充電
    .build()

val uploadRequest = OneTimeWorkRequestBuilder<ImageUploadWorker>()
    .setConstraints(constraints)
    .setInputData(workDataOf("IMAGE_URI" to "content://..."))
    .setBackoffCriteria(
        BackoffPolicy.EXPONENTIAL, // 指數退避 (越來越慢重試)
        OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
        TimeUnit.MILLISECONDS
    )
    .addTag("upload_tag") // 用於篩選或取消任務
    .build()

WorkManager.getInstance(context).enqueue(uploadRequest)

任務鏈與唯一任務

任務鏈 (Chaining)

你可以將多個任務串接,系統會保證順序執行,並將前一個任務的輸出傳遞給下一個。

WorkManager.getInstance(context)
    .beginWith(filterWork)      // 步驟 1: 濾鏡處理
    .then(compressWork)         // 步驟 2: 圖片壓縮
    .then(uploadWork)           // 步驟 3: 上傳伺服器
    .enqueue()

唯一任務 (Unique Work)

避免重複提交相同的長效任務(例如:重複點擊「立即備份」按鈕)。

WorkManager.getInstance(context).enqueueUniqueWork(
    "daily_sync",
    ExistingWorkPolicy.KEEP, // 如果已在隊列中,則保留舊的,忽略新的
    syncRequest
)

整合 Hilt 依賴注入

在大型專案中,Worker 通常需要呼叫 API 或資料庫,這時需要整合 Hilt

  1. 使用 @HiltWorker 註解。
  2. 在建構子加入 @AssistedInject
@HiltWorker
class SyncWorker @AssistedInject constructor(
    @Assisted context: Context,
    @Assisted params: WorkerParameters,
    private val repository: DataRepository // 注入你的單例
) : CoroutineWorker(context, params) { ... }

背景處理方案選擇指南

下表能幫助你根據任務特性選擇正確的技術:

任務特性建議技術範例
立即執行,使用者在看Coroutines / Flow獲取當前頁面列表
可延遲,與 UI 無關WorkManager雲端備份、資料同步
長時間進行,需通知用戶Foreground Service音樂播放、導航
精確時間點AlarmManager鬧鐘設定

透過 WorkManager,你能確保 App 在節省系統資源(如電量)的同時,仍具備高度的任務可靠性。