37 · 后台任务与定时执行
一句话定位:前端用 Service Worker / Web Worker 做后台与定时任务,Flutter 里对应 Isolate 计算 + workmanager 调度。但移动端后台是"系统说了算",不是"你说了算"——本篇讲清楚能做什么、怎么保活、什么时候别硬保活。
开篇速览
| 问题 | 答案 |
|---|---|
| 前端对应物 | Web Worker(并行计算)、Service Worker(后台同步/推送)、setInterval(定时) |
| 核心概念 | Isolate 并行计算;workmanager / background_fetch 系统调度;厂商通道保活 |
| 最常见误区 | 以为定时器能"永远在后台跑",实际上系统会掐死后台任务 |
| 一句话红线 | 后台执行时间/频率由操作系统决定;能靠"前台 + 推送"解决的需求,别做后台常驻 |
代码来源说明:HaierEnergy 当前
lib/有 Isolate 做计算(如数据压缩/解析)的使用痕迹,但未接入workmanager系统调度。 本篇按"通用能力 + 能源 App 场景建议"撰写。
一、三层后台能力
| 层 | 前端类比 | Flutter 方案 | 生命周期 |
|---|---|---|---|
| 并行计算 | Web Worker | compute / Isolate.run | App 活着时执行 |
| 系统调度任务 | Service Worker + 同步 | workmanager(Android WorkManager / iOS BGTaskScheduler) | 系统空闲时执行,时长/频率受限 |
| 实时后台能力 | 推送 / 长连接 | 厂商推送通道 / FCM / 前台 Service | 需用户授权 / 前台保活 |
二、Isolate:App 活着时的并行
密集计算(JSON 解析、加密、图片处理)不要阻塞 UI 线程:
dart
import 'dart:isolate';
// compute 是 Isolate 的最简封装:传一个顶级函数 + 参数
final parsed = await compute(parseLargeJson, rawJson);注意:Isolate 不共享内存,只能传值(SendPort 消息)。它解决的是"卡顿",不是"后台执行"。
三、workmanager:真正的系统调度
3.1 基本用法
dart
// 初始化并注册回调
Workmanager().initialize(callbackDispatcher, isInDebugMode: false);
// 注册周期任务(Android 最短 15 分钟;iOS 由系统决定时机)
Workmanager().registerPeriodicTask(
'sync_device_status',
'syncStatus',
frequency: const Duration(minutes: 15),
constraints: Constraints(networkType: NetworkType.connected),
);3.2 双端差异(必记)
| 平台 | 调度机制 | 真实保证 |
|---|---|---|
| Android | WorkManager | 受 Doze 省电模式约束,不是精确定时,可加约束(联网/充电) |
| iOS | BGTaskScheduler | 系统自主决定时机,无精确周期;background fetch 不可预期 |
结论:workmanager 适合"尽量在后台补一次同步",不适合"必须准点执行"。准点需求请看推送。
四、定时执行:你其实要的是"提醒/推送"
很多"定时任务"需求(如早上 8 点提醒查看电站)在移动端应该用本地通知/推送实现,而不是后台跑定时器:
| 需求 | 正确方案 |
|---|---|
| 每天固定时间提醒用户 | flutter_local_notifications 本地通知 |
| 服务端有事件要通知 | 推送通道(FCM / 厂商通道,见 24 篇) |
| 设备离线要告警 | 服务端检测 + 推送,不是客户端轮询 |
| 定时同步一次数据 | workmanager + 网络约束 |
| 周期性精确任务 | 服务端调度,客户端只在唤醒时执行 |
能源 App 的"设备离线告警""发电异常通知"应该走服务端推送,客户端后台轮询既费电又不可靠。
五、保活:厂商通道 vs 常驻进程
Android 国内厂商(小米/华为/OPPO/vivo)各有推送通道,App 被杀后只有厂商通道能唤活:
- 接入各厂商推送 SDK(或统一推送 U-Push / 厂商聚合 SDK);
- 拿到推送后,在回调里做"轻量同步",不能保证每次都执行;
- 不要通过"前台 Service + 空通知"硬保活:上架审核风险高、用户耗电投诉、厂商后台会杀。
保活的正确姿势是"借通道",不是"养进程"。
六、能源 App 场景落地建议
| 场景 | 推荐做法 |
|---|---|
| 设备状态上报 | 前台时定时上报;后台用 WorkManager 低频率补报 |
| 离线/异常告警 | 服务端检测 + 厂商推送(24 篇) |
| 数据压缩/解析 | compute Isolate,不阻塞 UI |
| 每日电站摘要 | 服务端定时生成 → 早 8 点本地通知/推送 |
| 蓝牙/传感器采集 | 前台 Service 方案(设备控制场景,详见 39 篇) |
动手练习
- 写一个
compute处理大 JSON 的示例,用flutter test验证不阻塞; - 用
workmanager注册一个"联网时同步"的周期任务,写清双端约束注释; - 把项目里的"设备离线提醒"改造成"服务端推送"方案,画出消息时序。
自检清单
- [ ] 能区分 Isolate(并行)/ workmanager(系统调度)/ 推送(实时唤醒)
- [ ] 知道 Android Doze 与 iOS BGTask 的"不可预期"约束
- [ ] 能在"定时任务"需求前先问"为什么不做推送/服务端调度"
- [ ] 知道厂商通道是保活的正确姿势,硬保活是反模式
常见误区
- "后台定时器能一直跑":系统会掐后台,
Timer只管 App 活着时; - "workmanager 精确到分钟":Android 最短 15 分钟且受 Doze 约束,iOS 完全由系统决定;
- "挂个前台 Service 就保活":上架风险 + 用户耗电投诉,厂商照杀;
- "后台轮询代替推送":费电且不可靠,服务端推送才是告警的正解。
相关文档
- 00 · 学习路线图 —— 阅读顺序
- 06 · Dart 异步并发与进阶语法 —— Isolate 原理
- 24 · 推送通知与深链接 —— 定时/告警的正确通道
- 39 · 设备通信-IoT协议 —— 蓝牙/传感器采集场景
- 22 · 性能分析与优化实战 —— 卡顿与 Isolate