写点什么

Flutter App 的启动流程,kotlin 单例模式

用户头像
Android架构
关注
发布于: 13 小时前

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


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


-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 方法做了两件事


  1. 初始化了一个 PipelineOwner 用于管理 RenderObject.

  2. 将_handlePersistentFrameCallback 这个 callback 传入 SchedulerBinding 中的_postFrameCallbacks 中,这样在硬件每次发出 VSync 信号的时候都会调用 RenderBinding 中的_handlePersistentFrameCallback 方法._handlePersistentFrameCallback 方法中直接调用了 drawFrame 方法。


因为在 WidgetsBinding 中实现了 drawFrame 方法,所以会调用 WidgetsBinding 中的 drawFrame 方法。 如下


void drawFrame() {...if (renderViewElement != null)buildOwner!.buildScope(renderViewElement!);//构建更新子树 super.drawFrame();

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Flutter App的启动流程,kotlin单例模式