Skip to content

WorkManager 后台任务

源:使用 WorkManager 调度任务

WorkManager 是 Android Jetpack 的一部分,用于处理即使在应用退出或设备重启后仍需运行的可延期异步任务。它会自动根据 API 级别选择最佳实现方式(JobScheduler, Firebase JobDispatcher, AlarmManager)。

适用场景:

  • 向后端服务器发送日志或分析数据。
  • 定期同步应用数据与服务器。
  • 上传图片或视频。

添加依赖

build.gradle (Module: app) 中添加:

kotlin
dependencies {
    val work_version = "2.9.0"

    // Kotlin + Coroutines
    implementation("androidx.work:work-runtime-ktx:$work_version")
}

定义 Worker

创建一个类继承自 Worker (或 CoroutineWorker 如果使用协程),并重写 doWork() 方法。这是执行后台任务的地方。

kotlin
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters

class UploadWorker(appContext: Context, workerParams: WorkerParameters):
    Worker(appContext, workerParams) {

    override fun doWork(): Result {

        // 接收输入数据
        val imageUriInput = inputData.getString("IMAGE_URI") ?: return Result.failure()

        return try {
            // 执行具体的耗时操作,例如上传图片
            uploadImage(imageUriInput)
            
            // 返回成功
            Result.success()
        } catch (throwable: Throwable) {
            // 返回失败,也可以返回 Result.retry() 进行重试
            Result.failure()
        }
    }

    private fun uploadImage(imageUri: String) {
        // 模拟上传逻辑
        Thread.sleep(3000) 
    }
}

使用 CoroutineWorker (推荐 Kotlin 用户):

kotlin
class CoroutineUploadWorker(appContext: Context, params: WorkerParameters) :
    CoroutineWorker(appContext, params) {

    override suspend fun doWork(): Result {
        // 可以在这里直接调用 suspend 函数
        return try {
            uploadImageSuspend()
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

创建 WorkRequest

有两种主要的请求类型:

  • OneTimeWorkRequest: 执行一次的任务。
  • PeriodicWorkRequest: 定期重复执行的任务。

一次性任务

kotlin
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.workDataOf

// 创建输入数据
val data = workDataOf("IMAGE_URI" to "http://...")

val uploadWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setInputData(data) // 传递数据
    .build()

定期任务

定期任务的时间间隔最少为 15 分钟。

kotlin
import androidx.work.PeriodicWorkRequestBuilder
import java.util.concurrent.TimeUnit

val saveRequest = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
    // .setConstraints(constraints)
    .build()

加急任务 (Expedited Work)

对于用户急需执行的任务(如发送即时消息),可以使用加急任务。系统会尽可能立即执行。

kotlin
val request = OneTimeWorkRequestBuilder<UploadWorker>()
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

兼容性

加急任务在 Android 12 (API 31) 及更高版本中利用了 JobScheduler 的加急队列。在旧版本中,它会委托给前台服务。因此,你必须在 Worker 中实现 getForegroundInfo() 以提供通知。

添加约束 (Constraints)

你可以指定任务运行的条件,例如仅在连接 Wi-Fi 或充电时运行。

kotlin
import androidx.work.Constraints
import androidx.work.NetworkType

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.UNMETERED) // 仅在不计量网络(Wi-Fi)下运行
    .setRequiresCharging(true) // 必须在充电时运行
    .build()

val myWorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setConstraints(constraints)
    .build()

提交任务

使用 WorkManager 提交请求。

kotlin
import androidx.work.WorkManager

WorkManager.getInstance(context).enqueue(myWorkRequest)

观察任务状态

可以通过 ID 或 Tag 观察任务的状态。

kotlin
WorkManager.getInstance(context).getWorkInfoByIdLiveData(uploadWorkRequest.id)
    .observe(this, Observer { workInfo ->
        if (workInfo != null && workInfo.state.isFinished) {
            // 任务完成
             if (workInfo.state == WorkInfo.State.SUCCEEDED) {
                 // 获取输出数据
                 val output = workInfo.outputData.getString("KEY")
             }
        }
    })

任务链 (Chaining Work)

可以将多个任务串联起来执行。

kotlin
WorkManager.getInstance(context)
    .beginWith(filterImageWorker) // 先执行滤镜
    .then(compressImageWorker)    // 然后压缩
    .then(uploadImageWorker)      // 最后上传
    .enqueue()

如果链中的任何任务返回 Result.failure(),整个链将停止执行。

取消任务

kotlin
// 通过 ID 取消
WorkManager.getInstance(context).cancelWorkById(uploadWorkRequest.id)

// 通过 Tag 取消 (如果在创建 Request 时设置了 addTag("syncTag"))
WorkManager.getInstance(context).cancelAllWorkByTag("syncTag")