Flutter App的启动流程,程序员进阶

一、开始的开始

**Android框架体系架构(高级UI+FrameWork源码)**这块知识是现今使用者最多的,我们称之Android2013~2016年的技术,但是,即使是这样的技术,Android开发者也往往因为网上Copy代码习惯了而导致对这块经常“使用”的代码 **熟悉而又陌生:**熟悉的是几乎天天在和它们打交道,天天在复制这些代码;陌生的是虽然天天和这些代码打交道,但是并没有深入研究过这些代码的原理,代码深处的内涵。

所以我们需要从新的角度去分析这些知识点,深入研究他们,要学习源码,模仿源码,然后再hook源码,这样才能说自己懂这块的知识。这些都是做Android开发,更是做高级工程师的基础。

其中需要注意的是

  • WidgetsBinding中的initInstances会初始化一个BuildOwner,处于管理widget和Element树
  • RendererBinding中的initInstances会初始化一个PipelineOwner,用于管理RenderObjct树,也会去创建一个callback,这个callback在每一帧刷新的时候都会调用

binding层和SingletonFlutterWindow,WidgetsFlutterBinding做交互。其中WidgetsFlutterBinding中的mixin都负责某一块的功能。

大致关系如下

2.png

WidgetsFlutterBinding.scheduleAttachRootWidget

WidgetsFlutterBinding实例化后会继续调用scheduleAttachRootWidget方法。实现如下

void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}

void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter(
container: renderView,
debugShortDescription: ‘[root]’,
child: rootWidget,
).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement?);
}

在上一篇文章我们说过attachRootWidget方法用于是为根widget生成一个根Element.生成Element调用了attachToRenderTree方法并传入了BuildOwner和Element. attachRootWidget的实现如下

RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement? 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 localPostFrameCallbacks =
List.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();
buildOwner!.finalizeTree();告诉buildOwner可以完成更新了,可以释放掉_inactiveElements

这个方法会先调用buildOwnerOwner的buildScope方法去构建和更新节点树。然后调用super.drawFrame()方法去调用RederBinding的drawFrame方法。如下

最后

都说三年是程序员的一个坎,能否晋升或者提高自己的核心竞争力,这几年就十分关键。

技术发展的这么快,从哪些方面开始学习,才能达到高级工程师水平,最后进阶到Android架构师/技术专家?我总结了这 5大块;

我搜集整理过这几年阿里,以及腾讯,字节跳动,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。
识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。
Android开发不会这些?如何面试拿高薪!

猜你喜欢

转载自blog.csdn.net/m0_61111814/article/details/124128181