Flutter 的 runApp 与三棵树诞生流程源码分析,带你轻松理解Android-Hook机制

//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 ]) {

//8、由于首次实例化RenderObjectToWidgetAdapter调用attachToRenderTree后才不为null,所以当前流程为null

if (element == null) {

//9、在lockState里面代码执行过程中禁止调用setState方法

owner.lockState(() {

//10、创建一个Element实例,即调用本段代码片段中步骤5的方法。

//调用RenderObjectToWidgetAdapter的createElement方法构建了一个RenderObjectToWidgetElement实例,继承RootRenderObjectElement,又继续继承RenderObjectElement,接着继承Element。

element = createElement();

assert(element != null);

//11、给根Element的owner属性赋值为WidgetsBinding初始化时实例化的BuildOwner实例。

element!.assignOwner(owner);

});

//12、重点!mount里面RenderObject

owner.buildScope(element!, () {

element!.mount(null, null);

});

} else {

//13、更新widget树时_newWidget赋值为新的,然后element数根标记为markNeedsBuild

element._newWidget = this;

element.markNeedsBuild();

}

return element!;

}

}

对于上面步骤 12 我们先进去简单看下 Element (RenderObjectToWidgetElement extends RootRenderObjectElement extends RenderObjectElement extends Element)的 mount 方法,重点关注的是父类 RenderObjectElement 中的 mount 方法,如下:

abstract class RenderObjectElement extends Element {

//1、Element树通过构造方法RenderObjectToWidgetElement持有了Widget树实例。(RenderObjectToWidgetAdapter)。

@override

RenderObjectWidget get widget => super.widget as RenderObjectWidget;

//2、Element树通过mount后持有了RenderObject渲染树实例。

@override

RenderObject

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

get renderObject => _renderObject!;

RenderObject? _renderObject;

@override

void mount(Element? parent, Object? newSlot) {

//3、通过widget树(即RenderObjectToWidgetAdapter)调用createRenderObject方法传入Element实例自己获取RenderObject渲染树。

//RenderObjectToWidgetAdapter.createRenderObject(this)返回的是RenderObjectToWidgetAdapter的container成员,也就是上面分析的RenderView渲染树根节点。

_renderObject = widget.createRenderObject(this);

}

}

到这里对于 Flutter 的灵魂“三棵树”来说也能得出如下结论:

  • Widget 树的根结点是 RenderObjectToWidgetAdapter(继承自 RenderObjectWidget extends Widget),我们 runApp 中传递的 Widget 树就被追加到了这个树根的 child 属性上。

  • Element 树的根结点是 RenderObjectToWidgetElement(继承自 RootRenderObjectElement extends RenderObjectElement extends Element),通过调用 RenderObjectToWidgetAdapter 的 createElement 方法创建,创建 RenderObjectToWidgetElement 的时候把 RenderObjectToWidgetAdapter 通过构造参数传递进去,所以 Element 的 _widget 属性值为 RenderObjectToWidgetAdapter 实例,也就是说 Element 树中 _widget 属性持有了 Widget 树实例。RenderObjectToWidgetAdapter 。

  • RenderObject 树的根结点是 RenderView(RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>),在 Element 进行 mount 时通过调用 Widget 树(RenderObjectToWidgetAdapter)的createRenderObject方法获取 RenderObjectToWidgetAdapter 构造实例化时传入的 RenderView 渲染树根节点。

上面代码流程对应的时序图大致如下:

在这里插入图片描述

结合上一小结可以很容易看出来三棵树的创建时机(时序图中紫红色节点),也可以很容易看出来 Element 是 Widget 和 RenderObject 之前的一个“桥梁”,其内部持有了两者树根,抽象表示如下:

在这里插入图片描述

由于篇幅和本文主题原因,我们重心关注三棵树的诞生流程,对于三棵树之间如何配合进行绘制渲染这里先不展开,后面会专门一篇分析。

热身帧绘制

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

到此让我们先将目光再回到一开始runApp方法的实现中,我们还差整个方法实现中的最后一个scheduleWarmUpFrame()调用,如下:

mixin SchedulerBinding on BindingBase {

void scheduleWarmUpFrame() {

Timer.run(() {

assert(_warmUpFrame);

handleBeginFrame(null);

});

Timer.run(() {

assert(_warmUpFrame);

handleDrawFrame();

//重置时间戳,避免热重载情况从热身帧到热重载帧的时间差,导致隐式动画的跳帧情况。

resetEpoch();

if (hadScheduledFrame)

scheduleFrame();

});

//在此次绘制结束前该方法会锁定事件分发,可保证绘制过程中不会再触发新重绘。

//也就是说在本次绘制结束前不会响应各种事件。

lockEvents(() async {

await endOfFrame;

Timeline.finishSync();

});

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值