Flutter App 的启动流程,kotlin 单例模式
SingletonFlutterWindow 继承自 FlutterView。也就继承了 platformDispatcher。也就是说 SingletonFlutterWindow 是通过 platformDispatcher 去处理来自 Flutter engine 层的事件, platformDispatcher 将 flutter engine 的事件分发到 SingletonFlutterWindow,把 SingletonFlutterWindow 的事件传给 flutter engine。
注意一下,BindingBase 里面也有一个 platformDispatcher,BindingBase 和 FlutterView 中的 platformDispatcher 是同一个。
WidgetsFlutterBinding.ensureInitialized()
现在说回 WidgetsFlutterBinding,当在 runApp 中调用了 WidgetsFlutterBinding.ensureInitialized 的时候,会返回一个 instance.如果 instance 为空,则调用默认的构造函数去创建一个 instance。
默认构造函数在 BindingBase 的实现如下
BindingBase() {...initInstances();//实例化...initServiceExtensions();//注册服务...}
因为 WidgetsFlutterBinding 最后 with 的是 WidgetsBinding 了,WidgetsBinding 是继承了 BindingBase,ServicesBinding,SchedulerBinding,PaintingBinding,GestureBinding,RendererBinding,SemanticsBinding。所以这些 mixin 的 initInstances 和 initServiceExtensions 方法也会一并执行。WidgetsFlutterBinding 和其 with 的 mixin 都会一同实例化并注册服务。
其中各个 mixin 负责的部分如下
BindingBase 各个 binding 相关的 mixin 的基类
ServicesBinding 处理与原生的交互通道
GestureBinding 处理手势
RendererBinding 处理渲染
PaintingBinding 处理绘制相关
SemanticsBinding 处理语义化
WidgetsBinding 处理 widget
其中需要注意的是
WidgetsBinding 中的 initInstances 会初始化一个 BuildOwner,处于管理 widget 和 Element 树
RendererBinding 中的 initInstances 会初始化一个 PipelineOwner,用于管理 RenderObjct 树,也会去创建一个 callback,这个 callback 在每一帧刷新的时候都会调用
binding 层和 SingletonFlutterWindow,WidgetsFlutterBinding 做交互。其中 WidgetsFlutterBinding 中的 mixin 都负责某一块的功能。
大致关系如下
![2.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/365d046a39f84f54a25a8b07737f808e~tplv-k3u1fbpfcp
-watermark.image)
WidgetsFlutterBinding.scheduleAttachRootWidget
WidgetsFlutterBinding 实例化后会继续调用 scheduleAttachRootWidget 方法。实现如下
void scheduleAttachRootWidget(Widget rootWidget) {Timer.run(() {attachRootWidget(rootWidget);});}
void attachRootWidget(Widget rootWidget) {_readyToProduceFrames = true;_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(container: renderView,debugShortDescription: '[root]',child: rootWidget,).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);}
在上一篇文章我们说过 attachRootWidget 方法用于是为根 widget 生成一个根 Element.生成 Element 调用了 attachToRenderTree 方法并传入了 BuildOwner 和 Element. attachRootWidget 的实现如下
RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {if (element == null) {owner.lockState(() {element = createElement();assert(element != null);element!.assignOwner(owner);});owner.buildScope(element!, () {element!.mount(null, null);});// This is most likely the first time the framework is ready to produce// a frame. Ensure that we are asked for one.SchedulerBinding.instance!.ensureVisualUpdate();} else {element._newWidget = this;element.markNeedsBuild();}return element!;}
这里的处理逻辑我在上一篇文章也讲到过,具体关于节点树的构建可以参看上一篇文章。当 element 为空时,会调用 SchedulerBinding.instance!.ensureVisualUpdate()的方法。这一个方法也很重要,经过下面的过程
ensureVisualUpdate() -> scheduleFrame() -> ensureFrameCallbacksRegistered()
最终会调用 ensureFrameCallbacksRegistered 方法,ensureFrameCallbacksRegistered 方法如下
void ensureFrameCallbacksRegistered() {window.onBeginFrame ??= _handleBeginFrame;window.onDrawFrame ??= _handleDrawFrame;}
经过一些列的调用,最终会把 SchedulerBinding 中的_handleBeginFrame 和_handleDrawFrame 这两个 callback 传给 WidgetsFlutterBinding 类的 window
set onBeginFrame(FrameCallback? callback) {platformDispatcher.onBeginFrame = callback;}set onDrawFrame(VoidCallback? callback) {platformDispatcher.onDrawFrame = callback;
可以看到,window 中的方法会把 callback 传给 platformDispatcher。 也就是说 WidgetsFlutterBinding.scheduleAttachRootWidget 这个方法经过一系列的方法调用后,最终会把 SchedulerBinding 这个 mixin 的_handleBeginFrame 和_handleDrawFrame 传给 platformDispatcher。
前面说到,platformDispatcher 分发来自 enginee 的事件。而在这里 SingletonFlutterWindow 把 platformDispatcher 的 onBeginFrame 和 onDrawFrame 这两个事件交给 SchedulerBinding 处理。
当硬件发出 VSync 信号时后,就会调用 platformDispatcher 的 onDrawFrame。从上面可知,实际上会调用 SchedulerBinding 中的_handleDrawFrame 方法。_handleDrawFrame 会调用 handleDrawFrame 方法。handleDrawFrame 方法定义如下
void handleDrawFrame() {..._schedulerPhase = SchedulerPhase.postFrameCallbacks;final List<FrameCallback> localPostFrameCallbacks =List<FrameCallback>.from(_postFrameCallbacks);_postFrameCallbacks.clear();for (final FrameCallback callback in localPostFrameCallbacks)_invokeFrameCallback(callback, _currentFrameTimeStamp!);...
其中的_postFrameCallbacks 里面存储的是 callback,作用是硬件每次发出 VSync 信号的时候都会调用。
这个方法里面会取出_postFrameCallbacks 里面所有的 callback,然后执行 callback。这里的_postFrameCallbacks 是在 RenderBinding 这个 mixin 的 initInstances 方法中传入的,如下
void initInstances() {super.initInstances();_instance = this;_pipelineOwner = PipelineOwner(onNeedVisualUpdate: ensureVisualUpdate,onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,);...addPersistentFrameCallback(_handlePersistentFrameCallback);...}
在 RenderBinding 的 initInstances 方法做了两件事
初始化了一个 PipelineOwner 用于管理 RenderObject.
将_handlePersistentFrameCallback 这个 callback 传入 SchedulerBinding 中的_postFrameCallbacks 中,这样在硬件每次发出 VSync 信号的时候都会调用 RenderBinding 中的_handlePersistentFrameCallback 方法._handlePersistentFrameCallback 方法中直接调用了 drawFrame 方法。
因为在 WidgetsBinding 中实现了 drawFrame 方法,所以会调用 WidgetsBinding 中的 drawFrame 方法。 如下
void drawFrame() {...if (renderViewElement != null)buildOwner!.buildScope(renderViewElement!);//构建更新子树 super.drawFrame();
评论