WorkManager是怎样工作的
目次
在 Android 开发中,WorkManager 是官方推荐的后台任务管理框架。它的特点是 任务可靠执行,即便应用退出或设备重启,也能保证任务最终执行。本文尝试从源码和运行机制角度梳理 WorkManager 的执行逻辑。
一个最简单的例子 #
|
|
UploadWorker
:自定义任务。enqueue()
:将任务加入队列。WorkManager
是单例,内部依赖 Application 实例,并通过Provider.Configuration
提供配置(线程池、协程上下文等)。
WorkManager 的关键点 #
- 基于队列思想:和常见任务队列类似,支持依赖、状态跟踪。
- 持久化任务信息:任务存储在数据库中,确保系统杀进程后还能恢复。
- 多种调度器实现:底层通过
JobScheduler
、GCM
或AlarmManager
触发执行。
任务入队:数据库层面 #
数据库核心表:WorkSpec
WorkSpec:存储一个逻辑工作单元的全部信息(id、约束条件、状态等)。
入队时的逻辑:
依赖检查
- 确保所有父任务已经入库(通过 id 判断)。
- 根据任务名称和策略(
APPEND
、KEEP
等)处理冲突。
常见策略
APPEND
/APPEND_OR_REPLACE
- 记录已有任务的依赖 id。
- 如果依赖被取消或失败,删除相关任务。
KEEP
- 已有任务状态为
ENQUEUED
或RUNNING
时,忽略新任务。 - 否则删除旧任务,重新入库。
- 已有任务状态为
插入新记录
- 判断前置任务和执行状态,更新状态。
- 插入数据库(
WorkSpec
、依赖表、标签表、名称表)。 - 返回是否需要实际执行(
state == ENQUEUED
)。
任务执行过程 #
当任务需要执行时:
标记执行状态
- 队列中触发条件(如 ContentUri)满足。
- 状态非完成的任务被调度。
调度器决定执行方式 WorkManager 会在初始化时选择一个合适的
Scheduler
:- API 23+ →
SystemJobScheduler
(基于JobScheduler
) - 旧设备 → 优先用
GcmScheduler
(若有 GCM),否则用SystemAlarmScheduler
(基于AlarmManager
)
- API 23+ →
执行逻辑
SystemJobScheduler
保存状态,将
WorkSpec
与系统JobInfo
绑定。JobInfo
配置条件:- 充电 / 空闲 / 网络约束
- API 29 前至少需要一个条件(默认延迟)
- 前台任务标记
- API 24+ 支持
ContentUri Trigger
- API 26+ 支持低电量 / 低存储约束
API 23 的特殊情况:只有当队列里有两个任务时才会触发 → 会补充一个任务保证执行。
SystemAlarmScheduler
- 直接通过
startService()
粗暴触发。
- 直接通过
Worker 的创建与绑定 #
执行时,WorkManager 根据数据库中的 WorkSpec
动态创建 Worker 实例:
|
|
这里的关键点:
- 没有直接传递 Worker 实例,而是通过 类名反射 +
WorkerFactory
创建。 - 数据库记录了任务的
workerClassName
和参数,确保任务可以在应用重启后恢复。
稳定执行的保障 #
WorkManager 的稳定性来源于以下几个方面:
- 持久化:所有任务与依赖存储在数据库中。
- 多重调度器适配:根据 API Level 和设备环境选择合适的调度方式。
- 状态机驱动:任务状态(
ENQUEUED
、RUNNING
、FAILED
、SUCCEEDED
等)严格受数据库驱动。 - WorkerFactory:确保任务实例可恢复,避免直接依赖内存对象。
总结 #
WorkManager 的核心是 数据库 + 调度器:
- 数据库 → 保证任务信息和状态持久化。
- 调度器 → 保证任务在合适条件下触发执行。
- WorkerFactory → 保证任务对象可恢复。
因此,无论应用进程是否被杀、设备是否重启,任务都能在条件满足时重新调度并最终执行。这也是 WorkManager 相比于直接使用 JobScheduler
、AlarmManager
的最大优势。
参考:
Categories: