Android WorkManager用法详解

220 阅读3分钟

WorkManager 是什么?

WorkManager 是 Android 用来执行后台任务的工具,适用于:

  • 执行一次的任务(比如:上传日志、备份数据)。
  • 定期执行的任务(比如:每 15 分钟同步数据)。
  • 即使应用关闭、设备重启后也能执行的任务。

1. 引入 WorkManager

先在 build.gradle.kts(模块级)中添加依赖:

dependencies {
    implementation("androidx.work:work-runtime-ktx:2.9.0") // WorkManager 最新版
}

然后 同步 Gradle(点击“Sync Now”)。


2. 创建 Worker

Worker 是 WorkManager 执行任务的地方。我们需要创建一个类,继承 WorkerCoroutineWorker(推荐)。

简单任务示例

新建一个 MyWorker.kt

import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
​
class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        Log.d("MyWorker", "后台任务正在执行...")
​
        // 假设任务执行成功
        return Result.success()
    }
}

3. 在应用中启动 WorkManager

MainActivity.kt 里启动这个任务:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
​
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
​
        // 创建一个任务
        val workRequest = OneTimeWorkRequest.Builder(MyWorker::class.java).build()
​
        // 启动任务
        WorkManager.getInstance(this).enqueue(workRequest)
    }
}

这样,每次启动应用,WorkManager 就会执行 MyWorker 里的代码。


4. 传递参数

如果 Worker 需要参数,比如下载文件的 URL,可以这样传递:

import androidx.work.Data
​
val data = Data.Builder()
    .putString("url", "https://example.com/file.jpg")
    .build()
​
val workRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
    .setInputData(data) // 传递参数
    .build()
​
WorkManager.getInstance(this).enqueue(workRequest)

然后在 MyWorker 里接收:

override fun doWork(): Result {
    val url = inputData.getString("url") ?: "未提供 URL"
    Log.d("MyWorker", "下载文件:$url")
​
    return Result.success()
}

5. 周期性任务

如果任务需要定期执行(比如每 15 分钟备份数据),可以用 PeriodicWorkRequest

import androidx.work.PeriodicWorkRequest
import java.util.concurrent.TimeUnit
​
val periodicWorkRequest = PeriodicWorkRequest.Builder(MyWorker::class.java, 15, TimeUnit.MINUTES)
    .build()
​
WorkManager.getInstance(this).enqueue(periodicWorkRequest)

⚠️ 注意:最小间隔是 15 分钟,不能更短!


6. 任务约束(例如仅在 WiFi 下运行)

可以加一些条件,比如:

  • 只有在 WiFi 连接 时运行。
  • 只有在 充电状态 时运行。
import androidx.work.Constraints
import androidx.work.NetworkType
​
val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.UNMETERED) // WiFi 才执行
    .setRequiresCharging(true) // 充电时才执行
    .build()
​
val workRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
    .setConstraints(constraints)
    .build()
​
WorkManager.getInstance(this).enqueue(workRequest)

7. 监听任务状态

如果想知道任务是否执行成功,可以这样:

val workManager = WorkManager.getInstance(this)
workManager.getWorkInfoByIdLiveData(workRequest.id).observe(this) { workInfo ->
    if (workInfo != null) {
        when (workInfo.state) {
            WorkInfo.State.ENQUEUED -> Log.d("MyWorker", "任务等待中")
            WorkInfo.State.RUNNING -> Log.d("MyWorker", "任务执行中")
            WorkInfo.State.SUCCEEDED -> Log.d("MyWorker", "任务成功")
            WorkInfo.State.FAILED -> Log.d("MyWorker", "任务失败")
            WorkInfo.State.CANCELLED -> Log.d("MyWorker", "任务已取消")
        }
    }
}

8. 取消任务

可以随时取消任务:

WorkManager.getInstance(this).cancelWorkById(workRequest.id) // 取消某个任务
WorkManager.getInstance(this).cancelAllWork() // 取消所有任务

9. 链式任务(Chained Work)

  • 作用: 如果有多个任务需要依次执行,比如先下载数据再处理数据,可以把它们链接起来。

  • 简单例子:

    val workA = OneTimeWorkRequestBuilder<WorkerA>().build()
    val workB = OneTimeWorkRequestBuilder<WorkerB>().build()
    val workC = OneTimeWorkRequestBuilder<WorkerC>().build()
    ​
    WorkManager.getInstance(context)
        .beginWith(workA)   // 先执行 workA
        .then(workB)        // workA 执行完后再执行 workB
        .then(workC)        // workB 执行完后再执行 workC
        .enqueue()          // 提交整个链条任务
    

    这样就能保证任务按照你设定的顺序依次完成。


10. 唯一任务(Unique Work)

  • 作用: 防止同样的任务重复执行。比如不希望同时有两个相同的任务在运行。

  • 简单例子:

    val uniqueWorkRequest = OneTimeWorkRequestBuilder<MyWorker>().build()
    
    WorkManager.getInstance(context).enqueueUniqueWork(
        "uniqueTask",                  // 给任务起一个唯一的名字
        ExistingWorkPolicy.REPLACE,    // 如果已有同名任务,替换掉旧的任务
        uniqueWorkRequest
    )
    

    使用唯一任务可以确保同一时刻不会有多个相同任务重复运行。

总结

功能代码
一次性任务OneTimeWorkRequest.Builder(MyWorker::class.java).build()
周期性任务PeriodicWorkRequest.Builder(MyWorker::class.java, 15, TimeUnit.MINUTES).build()
传递参数Data.Builder().putString("key", "value").build()
添加约束Constraints.Builder().setRequiredNetworkType(NetworkType.UNMETERED).build()
监听任务状态workManager.getWorkInfoByIdLiveData(id).observe(...)
取消任务WorkManager.getInstance(this).cancelWorkById(id)

适用场景

  • 一次性任务(如:上传日志、备份数据库)。
  • 定期任务(如:自动同步数据,每天上传一次)。
  • 后台任务(如:下载大文件)。
  • 任务可以应用退出后执行(如:应用关闭后仍继续备份数据)。

❌ WorkManager 不能做的事情

  • 定时精准任务(比如定点 3:00AM 运行,推荐用 AlarmManager)。
  • 即时任务(如果任务必须立刻完成,建议用 ForegroundService)。