- 提供接口调用用来触发渲染。
*/
_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 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();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
总结
【Android 详细知识点思维脑图(技能树)】
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。
这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
到了哪个阶段就好。
虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。
这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。
[外链图片转存中…(img-BsmKLg6i-1711930331206)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。