2024年Flutter 的 runApp 与三棵树诞生流程源码分析,2024年最新蚂蚁金服第三面面试什么

最后

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

腾讯、字节跳动、阿里、百度等BAT大厂 2019-2021面试真题解析

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 位置:FLUTTER_SDK\packages\flutter\lib\src\widgets\binding.dart

  • 注意:app参数的Widget布局盒子约束constraints会被强制为填充屏幕,这是框架机制,自己想要调整可以用Align等包裹。

  • 多次重复调用runApp将会从屏幕上移除已添加的app Widget并添加新的上去,

  • 框架会对新的Widget树与之前的Widget树进行比较,并将任何差异应用于底层渲染树,有点类似于StatefulWidget

调用State.setState后的重建机制。

*/

void runApp(Widget app) {

WidgetsFlutterBinding.ensureInitialized()

…scheduleAttachRootWidget(app)

…scheduleWarmUpFrame();

}

可以看到上面三行代码代表了 Flutter 启动的核心三步(级联运算符调用):

  1. WidgetsFlutterBinding 初始化(ensureInitialized()

  2. 绑定根节点创建核心三棵树(scheduleAttachRootWidget(app)

  3. 绘制热身帧(scheduleWarmUpFrame()

WidgetsFlutterBinding 实例及初始化

========================================================================================

直接看源码,如下:

class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {

static WidgetsBinding ensureInitialized() {

if (WidgetsBinding.instance == null)

WidgetsFlutterBinding();

return WidgetsBinding.instance!;

}

}

WidgetsFlutterBinding 继承自 BindingBase,并且 with 了大量的 mixin 类。WidgetsFlutterBinding 就是将 Widget 架构和 Flutter Engine 连接的核心桥梁,也是整个 Flutter 的应用层核心。通过 ensureInitialized() 方法我们可以得到一个全局单例的 WidgetsFlutterBinding 实例,且 mixin 的一堆 XxxBinding 也被实例化。

BindingBase 抽象类的构造方法中会调用initInstances()方法,而各种 mixin 的 XxxBinding 实例化重点也都在各自的initInstances()方法中,每个 XxxBinding 的职责不同,如下:

  • WidgetsFlutterBinding:核心桥梁主体,Flutter app 全局唯一。

  • BindingBase:绑定服务抽象类。

  • GestureBinding:Flutter 手势事件绑定,处理屏幕事件分发及事件回调处理,其初始化方法中重点就是把事件处理回调_handlePointerDataPacket函数赋值给 window 的属性,以便 window 收到屏幕事件后调用,window 实例是 Framework 层与 Engine 层处理屏幕事件的桥梁。

  • SchedulerBinding:Flutter 绘制调度器相关绑定类,debug 编译模式时统计绘制流程时长等操作。

  • ServicesBinding:Flutter 系统平台消息监听绑定类。即 Platform 与 Flutter 层通信相关服务,同时注册监听了应用的生命周期回调。

  • PaintingBinding:Flutter 绘制预热缓存等绑定类。

  • SemanticsBinding:语义树和 Flutter 引擎之间的粘合剂绑定类。

  • RendererBinding:渲染树和 Flutter 引擎之间的粘合剂绑定类,内部重点是持有了渲染树的根节点。

  • WidgetsBinding:Widget 树和 Flutter 引擎之间的粘合剂绑定类。

从 Flutter 架构宏观抽象看,这些 XxxBinding 承担的角色大致是一个桥梁关联绑定,如下:

在这里插入图片描述

本文由于是启动主流程相关机制分析,所以初始化中我们需要关注的主要是 RendererBinding 和 WidgetsBinding 类的initInstances()方法,如下:

mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {

@override

void initInstances() {

/**

*1、创建一个管理Widgets的类对象

*BuildOwner类用来跟踪哪些Widget需要重建,并处理用于Widget树的其他任务,例如管理不活跃的Widget等,调试模式触发重建等。

*/

_buildOwner = BuildOwner();

//2、回调方法赋值,当第一个可构建元素被标记为脏时调用。

buildOwner!.onBuildScheduled = _handleBuildScheduled;

//3、回调方法赋值,当本地配置变化或者AccessibilityFeatures变化时调用。

window.onLocaleChanged = handleLocaleChanged;

window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;

}

}

mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {

@override

void initInstances() {

/**

  • 4、创建管理rendering渲染管道的类

  • 提供接口调用用来触发渲染。

*/

_pipelineOwner = PipelineOwner(

onNeedVisualUpdate: ensureVisualUpdate,

onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,

onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,

);

//5、一堆window变化相关的回调监听

window

…onMetricsChanged = handleMetricsChanged

…onTextScaleFactorChanged = handleTextScaleFactorChanged

…onPlatformBrightnessChanged = handlePlatformBrightnessChanged

…onSemanticsEnabledChanged = _handleSemanticsEnabledChanged

…onSemanticsAction = _handleSemanticsAction;

//6、创建RenderView对象,也就是RenderObject渲染树的根节点

initRenderView();

}

void initRenderView() {

//RenderView extends RenderObject with RenderObjectWithChildMixin

//7、渲染树的根节点对象

renderView = RenderView(configuration: createViewConfiguration(), window: window);

renderView.prepareInitialFrame();

}

//定义renderView的get方法,获取自_pipelineOwner.rootNode

RenderView get renderView => _pipelineOwner.rootNode! as RenderView;

//定义renderView的set方法,上面initRenderView()中实例化赋值就等于给_pipelineOwner.rootNode也进行了赋值操作。

set renderView(RenderView value) {

assert(value != null);

_pipelineOwner.rootNode = value;

}

}

到此基于初始化过程我们已经得到了一些重要信息,请记住 RendererBinding 中的 RenderView 就是 RenderObject 渲染树的根节点。上面这部分代码的时序图大致如下:

在这里插入图片描述

通过 scheduleAttachRootWidget 创建关联三棵核心树

=================================================================================================

WidgetsFlutterBinding 实例化单例初始化之后先调用了scheduleAttachRootWidget(app)方法,这个方法位于 mixin 的 WidgetsBinding 类中,本质是异步执行了attachRootWidget(rootWidget)方法,这个方法完成了 Flutter Widget 到 Element 到 RenderObject 的整个关联过程。源码如下:

mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {

@protected

void scheduleAttachRootWidget(Widget rootWidget) {

//简单的异步快速执行,将attachRootWidget异步化

Timer.run(() {

attachRootWidget(rootWidget);

});

}

void attachRootWidget(Widget rootWidget) {

//1、是不是启动帧,即看renderViewElement是否有赋值,赋值时机为步骤2

final bool isBootstrapFrame = renderViewElement == null;

_readyToProduceFrames = true;

//2、桥梁创建RenderObject、Element、Widget关系树,_renderViewElement值为attachToRenderTree方法返回值

_renderViewElement = RenderObjectToWidgetAdapter(

//3、RenderObjectWithChildMixin类型,继承自RenderObject,RenderObject继承自AbstractNode。

//来自RendererBinding的_pipelineOwner.rootNode,_pipelineOwner来自其初始化initInstances方法实例化的PipelineOwner对象。

//一个Flutter App全局只有一个PipelineOwner实例。

container: renderView,

debugShortDescription: ‘[root]’,

//4、我们平时写的dart Widget app

child: rootWidget,

//5、attach过程,buildOwner来自WidgetsBinding初始化时实例化的BuildOwner实例,renderViewElement值就是_renderViewElement自己,此时由于调用完appach才赋值,所以首次进来也是null。

).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement?);

if (isBootstrapFrame) {

//6、首帧主动更新一下,匹配条件的情况下内部本质是调用SchedulerBinding的scheduleFrame()方法。

//进而本质调用了window.scheduleFrame()方法。

SchedulerBinding.instance!.ensureVisualUpdate();

}

}

}

上面代码片段的步骤 2 和步骤 5 需要配合 RenderObjectToWidgetAdapter 类片段查看,如下:

//1、RenderObjectToWidgetAdapter继承自RenderObjectWidget,RenderObjectWidget继承自Widget

class RenderObjectToWidgetAdapter extends RenderObjectWidget {

//3、我们编写dart的runApp函数参数中传递的Flutter应用Widget树根

final Widget? child;

//4、继承自RenderObject,来自PipelineOwner对象的rootNode属性,一个Flutter App全局只有一个PipelineOwner实例。

final RenderObjectWithChildMixin container;

//5、重写Widget的createElement实现,构建了一个RenderObjectToWidgetElement实例,它继承于Element。

//Element树的根结点是RenderObjectToWidgetElement。

@override

RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this);

//6、重写Widget的createRenderObject实现,container本质是一个RenderView。

//RenderObject树的根结点是RenderView。

@override

RenderObjectWithChildMixin createRenderObject(BuildContext context) => container;

@override

void updateRenderObject(BuildContext context, RenderObject renderObject) { }

/**

*7、上面代码片段中RenderObjectToWidgetAdapter实例创建后调用

*owner来自WidgetsBinding初始化时实例化的BuildOwner实例,element 值就是自己。

*该方法创建根Element(RenderObjectToWidgetElement),并将Element与Widget进行关联,即创建WidgetTree对应的ElementTree。

*如果Element已经创建过则将根Element中关联的Widget设为新的(即_newWidget)。

*可以看见Element只会创建一次,后面都是直接复用的。

*/

RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement? element ]) {

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ment ]) {

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 15
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值