WorkManager 是什么?

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

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

1. 引入 WorkManager

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

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

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


2. 创建 Worker

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

简单任务示例

新建一个 MyWorker.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
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 里启动这个任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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,可以这样传递:

1
2
3
4
5
6
7
8
9
10
11
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 里接收:

1
2
3
4
5
6
override fun doWork(): Result {
val url = inputData.getString("url") ?: "未提供 URL"
Log.d("MyWorker", "下载文件:$url")

return Result.success()
}

5. 周期性任务

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

1
2
3
4
5
6
7
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 连接 时运行。
  • 只有在 充电状态 时运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
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. 监听任务状态

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

1
2
3
4
5
6
7
8
9
10
11
12
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. 取消任务

可以随时取消任务:

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

9. 链式任务(Chained Work)

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

  • 简单例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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)

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

  • 简单例子:

    1
    2
    3
    4
    5
    6
    7
    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)。