WorkManager 如何保证任务在设备重启后仍能执行?
解读
面试官想确认两点:
- 你是否真的“用过”WorkManager,而不是只写 demo;
- 你是否理解 Android 8.0 之后后台限制收紧、国产 ROM 杀进程、厂商省电策略等国内现实下,WorkManager 靠什么机制还能把任务捞回来。
答“因为加了 KEEP 约束”或“系统会重启 Worker”都太空,必须落到:
- 任务落库 → 开机广播 → 系统 JobScheduler/AlarmManager → 厂商白名单 → 国内实测经验
四个环节缺一不可。
知识点
- Room 持久化:WorkManager 内置 androidx.work.impl.WorkDatabase,任务、约束、中间状态全部落盘,进程被杀、重启不影响记录。
- 开机自启:AndroidManifest 中注册 androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryChargingProxy 等 6 个 Proxy 以及 SystemBootReceiver,接收 BOOT_COMPLETED 广播,无需应用声明权限即可拉起 WorkManager 内部进程。
- 调度器兜底:API 23+ 优先走 JobScheduler,14-22 走 AlarmManager+BroadcastReceiver;WorkManager 在重启后会重新把数据库里所有未完成的 WorkSpec 重新丢进调度器。
- 约束重算:重启后电量、网络、存储等约束重新采样,只有满足条件才触发,不满足则继续等待下一次约束变更。
- 国内兼容:
- 华为/小米/OPPO 等“自启动”权限默认关闭,需要引导用户在系统设置里手动打开,否则 BOOT_COMPLETED 被拦截;
- 部分 ROM 把 JobScheduler 采样间隔拉到 15-30 min,建议业务允许 0 延迟时用 setExpedited(WorkRequest.FOREGROUND_SERVICE expedited) 或前台服务通道;
- 若业务强依赖,可再叠加厂商 Push SDK 做双通道保险。
- 调试验证:adb shell am broadcast -a android.intent.action.BOOT_COMPLETED 模拟重启,通过 adb shell dumpsys jobscheduler | grep your.package 查看任务是否重新进入队列。
答案
“WorkManager 在应用进程外把任务持久化到 Room 数据库,因此即使进程被杀或设备重启,记录依然存在。
重启后,系统发出 BOOT_COMPLETED 广播,WorkManager 内部的 SystemBootReceiver 会被唤醒,无需应用额外权限。
接着 WorkManager 把数据库里所有未完成的 WorkSpec 重新注册到 JobScheduler(API 23+)或 AlarmManager(低版本),并重新计算电量、网络等约束。
只要约束满足,系统就会在合适时机把任务拉回应用进程执行;不满足则继续等待。
在国内环境下,需要额外注意厂商对自启动权限的限制,建议引导用户手动开启并做线上埋点验证成功率;对时效性强的任务可再叠加前台服务或厂商 Push 作为双保险。”
拓展思考
- 如果用户把应用“卸载重装”或“清除数据”,数据库被删,任务自然丢失,此时只能依赖服务端轮询或 Push 重下任务。
- 对“必须今天内执行但可延迟”的场景,可用 OneTimeWorkRequest 加 setInitialDelay + setBackoffCriteria,配合 setExpedited 进入前台队列,既省电又提升到达率。
- 折叠屏、多用户、工作资料夹等场景下,BOOT_COMPLETED 只发给主用户,WorkManager 会遍历所有用户空间重新调度,需验证 WorkProfile 下是否重复执行。
- Android 14 引入“重启后必须用户解锁才能执行”的隐私限制,可在 WorkRequest 里加 setRequiredDeviceIdle(false) 与 setRequiresDeviceIdle(false) 做兼容,同时关注 Google 后续是否开放新约束。