SchedulerBinding 的三个Frame回调

addPersistentFrameCallbackaddPostFrameCallbackaddTimingsCallback 确实都是 Flutter 框架调度中"Frame 级别"的回调,但三者触发时机完全不同, 它们分别连接着 Frame 生命周期的三个阶段。 一个详细、专业但清晰的对照和时间线讲解 👇


🧭 一、概览表

回调接口 注册位置 执行时机(帧流程阶段) 回调线程 常见用途 是否每帧持续触发
addPersistentFrameCallback SchedulerBinding 在每帧开始时,绘制流程开始之前(布局、绘制前) UI Thread(Dart isolate) 自定义动画、同步逻辑、监控 frame build ✅ 是,每帧都会触发
addPostFrameCallback WidgetsBinding 帧绘制完成后、但在下一帧开始前(UI 树渲染结束) UI Thread(Dart isolate) 在 build 完后执行一次性逻辑(如状态恢复、测量布局等) ❌ 否,只执行一次
addTimingsCallback SchedulerBinding 一帧真正完成后(包括 rasterizer 渲染、GPU 提交) Engine ➜ Dart isolate 性能分析、帧率统计、掉帧检测 ⚙️ 仅在帧真正渲染完成时触发(由 Engine 主动回调)

🧩 二、完整帧生命周期时间线图

下面是一帧从触发到结束的时间轴:

scss 复制代码
┌──────────────────────────────────────────────────────────────┐
│ 一帧的完整生命周期(Flutter Pipeline)                       │
├──────────────────────────────────────────────────────────────┤
│ vsync 信号到达 → 触发 Scheduler.handleBeginFrame             │
│      ↓                                                       │
│ ① addPersistentFrameCallback() 触发                          │ ← 每帧都会调用(UI逻辑)
│      ↓                                                       │
│ Widgets build/rebuild/layout/paint 完成                      │
│      ↓                                                       │
│ ② addPostFrameCallback() 执行                                │ ← 本帧后执行一次(UI在屏幕前执行的最后逻辑)
│      ↓                                                       │
│ UI 层命令发送给 Engine,Rasterizer 开始渲染 → GPU            │
│      ↓                                                       │
│ ③ addTimingsCallback() 触发                                 │ ← Engine 通知 Dart:此帧渲染周期完结
│      ↓                                                       │
│ 下一帧 vsync 周期开始                                         │
└──────────────────────────────────────────────────────────────┘

🧠 三、详细解释

1️⃣ addPersistentFrameCallback

  • 🔹 每当 Flutter engine 安排一次 Frame(vsync 信号触发)时调用;
  • 🔹 在 WidgetsBinding.drawFrame() 之前;
  • 🔹 多用于做动画同步,如 Ticker, AnimationController
  • 🔹 不可在里面直接调用 setState()(会导致无限循环)。
dart 复制代码
SchedulerBinding.instance.addPersistentFrameCallback((Duration timeStamp) {
  // 每帧都会执行一次
  // timeStamp:距离应用启动的时间
});

用途:开发 Frame 驱动逻辑、动画系统、心跳检测。


2️⃣ addPostFrameCallback

  • 🔹 注册一个下一帧绘制完成后执行的回调;
  • 🔹 只执行一次;
  • 🔹 常用于需要在 widget build 完之后去访问 context 或做布局调整。
dart 复制代码
WidgetsBinding.instance.addPostFrameCallback((_) {
  print("这一帧的Widget都build & render完毕之后执行");
});

用途:执行一次性的渲染后逻辑(比如弹框、滚动控制、布局测量)。


3️⃣ addTimingsCallback

  • 🔹 由 Flutter 引擎 在一帧完全渲染完成(包括 GPU 渲染)后回调;
  • 🔹 参数提供本帧的渲染性能信息:
    • build、rasterize 时间、
    • start/finish 时间戳;
  • 🔹 不一定每帧都有(只有当一帧真正提交给屏幕后才会触发)。
dart 复制代码
SchedulerBinding.instance.addTimingsCallback((List<FrameTiming> timings) {
  for (final t in timings) {
    print('build: ${t.buildDuration}, raster: ${t.rasterDuration}');
  }
});

用途:性能监控、丢帧检测、UI心跳。


🧩 四、对应的 Pipeline Phase(官方描述)

Scheduler Phase 回调接口 官方解释
TRANSIENT_CALLBACKS addPersistentFrameCallback 一帧准备阶段,执行持久 frame 回调
POST_FRAME_CALLBACKS addPostFrameCallback 当前帧绘制完毕后执行延迟回调
FrameTimings (engine reported) addTimingsCallback 一帧渲染完成,engine 向 Dart 报告

⚙️ 五、典型使用示例汇总

dart 复制代码
void main() {
  WidgetsFlutterBinding.ensureInitialized();

  // 每帧都会触发 - 可作心跳
  SchedulerBinding.instance.addPersistentFrameCallback((timeStamp) {
    print('Persistent at ${timeStamp.inMilliseconds}');
  });

  // 当前帧绘制完后执行一次
  WidgetsBinding.instance.addPostFrameCallback((_) {
    print('Widget build done.');
  });

  // 渲染完成后(含GPU提交)
  SchedulerBinding.instance.addTimingsCallback((timings) {
    final t = timings.last;
    print('Frame done. build=${t.buildDuration}, raster=${t.rasterDuration}');
  });

  runApp(MyApp());
}

✅ 最终总结表

回调 调用频率 触发时机 所属线程 典型用途
addPersistentFrameCallback 每帧 每帧开始(UI build 前) UI isolate 动画驱动、持续逻辑、心跳
addPostFrameCallback 一次 当前帧 build 后(UI 树构建完) UI isolate 布局调整、逻辑收尾
addTimingsCallback 条件触发 一帧 GPU 渲染完成后 Engine 调用 Dart 性能分析、渲染监控

🔥 一句总结记忆法:

Persistent ------ 每帧都来; Post ------ 帧后执行一次; Timings ------ 一帧真上屏后报告性能。


相关推荐
我狸才不是赔钱货9 分钟前
前端技术栈全景图:从HTML到现代框架的演进之路
前端·html
百花~37 分钟前
前端三剑客之一 HTML~
前端·html
lang201509281 小时前
Spring远程调用与Web服务全解析
java·前端·spring
listhi5203 小时前
利用React Hooks简化状态管理
前端·javascript·react.js
一点一木3 小时前
🚀 2025 年 10 月 GitHub 十大热门项目排行榜 🔥
前端·人工智能·github
华仔啊4 小时前
这个Vue3旋转菜单组件让项目颜值提升200%!支持多种主题,拿来即用
前端·javascript·css
非凡ghost4 小时前
Adobe Lightroom安卓版(手机调色软件)绿色版
前端·windows·adobe·智能手机·软件需求
BestAns5 小时前
Postman 平替?这款轻量接口测试工具,本地运行 + 批量回归超实用!
前端
专注前端30年5 小时前
Webpack进阶玩法全解析(性能优化+高级配置)
前端·webpack·性能优化
烛阴5 小时前
Lua世界的基石:变量、作用域与七大数据类型
前端·lua