Ray 的记录站

日常开发实践记录

0%

什么是 Flutter 的 Binding

利用 Window 作为接口, 通过 Binding 来建立 Engine 和 Framework 的联系.

Binding 的初始化过程实际就是将 Framework 端许多函数或方法挂接到 Window 上的过程. 绑定过程的结果是生成一个 WidgetsBinding 单例对象, 可通过 WidgetsBinding.instance 访问. 更极端地讲: 只有通过 Binding, Framework 和 Engine 才能相互通信(不过有一个特例是 RenderView).

在 Flutter 中有如下 Binding, 首先是比较重要的四个:

  • SchedulerBinding
  • GestureBinding
  • RendererBinding
  • WidgetsBinding

其他几个:

  • ServicesBinding: 主要负责处理平台通道中的消息传递.
  • PaintingBinding: 主要负责处理 image 缓存.
  • SemanticsBinding: 主要负责处理未来 Flutter 版本中的语义化相关内容.
  • TestWidgetsFlutterBinding: 用于测试库中的 Widget tests.

下图是这些 Binding 和 window 之间的交互关系:

通过代码来看, WidgetsFlutterBinding 仅负责启动整个绑定过程, 所有绑定都在 ensureInitialized 类方法中完成, 即根据 mixin 的顺序执行每个 Binding mixin 中的 initInstances 方法:

1
2
3
4
5
6
7
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding(); // 启动整个绑定流程, 因为在构造方法中有一系列的绑定调用
return WidgetsBinding.instance;
}
}

而其中核心是 initInstances 串联起来的调用, 详见源码. (initInstances 里面的工作代码是从 GestureBinding -> WidgetsBinding 这样的顺序进行的).

下面介绍四个比较重要的 binding, 具体的源码解析会放到单独的章节中, 这里不展开说, 仅从顶层进行分析.

SchedulerBinding 概述

这个绑定主要负责执行三大类的 callback:

  • Transient callbacks: 由 window.onBeginFrame 驱动.
  • Persistent callbacks: 由 window.onDrawFrame 驱动.
  • Post-frame callbacks: 也是由 onDrawFrame 驱动, 但在 Persistent callbacks 执行之后.

另外它还负责执行一些非渲染类的工作, 这些工作一般是在两帧之间执行. 通过它内部的 schedulingStrategy 回调来决定这些工作的执行优先级. 默认值是 defaultSchedulingStrategy 方法.

它会监听应用的 lifecycle 事件(paused/resumed/inactive)来打开或关闭 _framesEnabled, 这个标志位控制能否向 window 发送 scheduleFrame() 消息:

  • resumed/inactive: 可以向 window 发送 scheduleFrame()
  • paused: 不可以向 window 发送 scheduleFrame()
  • 其他: 不改变当前状态

当它向 window 发送 scheduleFrame 消息后, window 会陆续调用它的 _handleBeginFrame_handleDrawFrame(挂接在 window 上的两个回调), 再通过它们来执行外部注册的三大类的 callback, 详见源码.

GestureBinding

这个绑定主要负责手势子系统, 包括光标事件的生命期和手势竞技场. 要明白 GestureBinding, 先要看 Flutter 中的手势系统, 有关手势系统的介绍, 会在 Flutter 手势系统一章中讲到.

RendererBinding

这个绑定的主要功能是作为 render tree 和 Flutter 引擎间的胶水.

WidgetsBinding

实际上帧渲染流程的核心实现是在 WidgetsBinding 中:

启动引擎-> main 函数 -> runApp -> RendererBinding 注册持久回调(addPersistentFrameCallback) -> _persistentCallbacks(在 window 收到 onDrawFrame 时被调用) -> RendererBinding 的那个持久回调会调用 drawFrame, 在 WidgetsBinding 上面的 -> 整个布局渲染过程执行一次 -> 生成一帧.

最后一个问题: build 是如何调用的?

比如 StatelessWidgetbuild 方法, 调用顺序为: StatelessWidget 的 build <- StatelessElement 的 build <- ComponentElement 的 performRebuild <- Element 的 performRebuild <- Element 的 rebuild (dirty element) <- buildScope <- WidgetsBinding 的 drawFrame, 而 drawFrame 又是由 onDrawFrame 中通过持久回调调用的, 这样就形成了一个完整流程. 当 build 执行完后, 实际就是更新了 Element 和 RenderObject 的配置, 然后通过这些信息来走一次渲染管线(在 RendererBinding 中的 drawFrame), 将合成的数据送入 GPU, 就完成了一帧的生成和显示.

onDrawFrame 是由外部事件触发的 window 向引擎发送 scheduleFrame, 再通过引擎反向调用 window 上的 onBeginFrame 和 onDrawFrame, 这样来触发的. 最开始的一帧是 main 函数主动向引擎发送消息生成的(scheduleWarmUpFrame), 后续的帧都是由外部事件触发生成的, 如果是连续帧变化, 就是动画而已.

下一个需要关注的内容是 Widget 和 Element 和 Render 的相互配合生成界面的相关原理.

相关参考