从上一篇文章 Widget,Element,RenderObject树的构建和更新流程 分析了Flutter中的节点的构建,从源码出发,说明节点是如何一步步地往下构建,在文章也提到了WidgetsFlutterBinding,可是没有细说。markdown
在这篇文章里面,主要分析App的构建过程,分析从runApp之后发生了什么事情。分析一下WidgetsFlutterBinding是什么东西app
文章后方也有一个流程图,能够经过看流程图了解app的启动流程函数
咱们的main函数里面,一般都会调用runApp(Widget app)方法,那这个方法里面到底作了什么呢?runApp的实现以下布局
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()//初始化
..scheduleAttachRootWidget(app)//绑定根widget
..scheduleWarmUpFrame();//确保尽快第一帧
}
复制代码
这个方法里面调用了WidgetsFlutterBinding的三个方法,分别用于初始化WidgetsFlutterBinding,和绑定widget,并开始构建页面。先分析一下这个WidgetsFlutterBinding是什么东西。post
Flutter中的Binding概念我理解为一个胶水层,负责链接framework和engine层,关系大体以下ui
runApp方法就是建立一个胶水层WidgetsFlutterBinding,并链接framework和engine层。this
WidgetsFlutterBinding是一个Binding的实例,也就是一条桥,负责链接Flutter的engine和framework的之间的事件交互。WidgetsFlutterBinding的定义以下spa
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类,并且这些mixin都是继承于BindingBase这个类debug
BindingBase这个类的方法比较多,抽出来与本文相关的一些方法,以下code
ui.SingletonFlutterWindow get window => ui.window;
ui.PlatformDispatcher get platformDispatcher => ui.PlatformDispatcher.instance;
void initInstances();
void initServiceExtensions();
复制代码
其中的这个window是SingletonFlutterWindow类型的,位于Flutter 的engine层。SingletonFlutterWindow就是咱们Flutter app加载的窗口,并且SingletonFlutterWindow是一个单例,它继承于FlutterView。
FlutterView中有一个方法
PlatformDispatcher get platformDispatcher;
复制代码
这个方法返回一个platformDispatcher,这个platformDispatcher是Flutter 的一个事件分发器,负责Flutter分发engine的事件,和传递事件给engine层。
SingletonFlutterWindow继承自FlutterView。也就继承了platformDispatcher。也就是说SingletonFlutterWindow是经过platformDispatcher去处理来自Flutter engine层的事件, platformDispatcher将flutter engine的事件分发到SingletonFlutterWindow,把SingletonFlutterWindow的事件传给flutter engine。
注意一下,BindingBase里面也有一个platformDispatcher,BindingBase和FlutterView中的platformDispatcher是同一个。
如今说回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负责的部分以下
其中须要注意的是
binding层和SingletonFlutterWindow,WidgetsFlutterBinding作交互。其中WidgetsFlutterBinding中的mixin都负责某一块的功能。
大体关系以下
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方法作了两件事
由于在WidgetsBinding中实现了drawFrame方法,因此会调用WidgetsBinding中的drawFrame方法。 以下
void drawFrame() {
...
if (renderViewElement != null)
buildOwner!.buildScope(renderViewElement!);//构建更新子树
super.drawFrame();
buildOwner!.finalizeTree();告诉buildOwner能够完成更新了,能够释放掉_inactiveElements
...
复制代码
这个方法会先调用buildOwnerOwner的buildScope方法去构建和更新节点树。而后调用super.drawFrame()方法去调用RederBinding的drawFrame方法。以下
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();//刷新布局
pipelineOwner.flushCompositingBits();//图层更新
pipelineOwner.flushPaint();//刷新绘制
if (sendFramesToEngine) {
renderView.compositeFrame(); // 告诉GPU渲染renderView
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
_firstFrameSent = true;
}
}
复制代码
这个方法会去调用去管理RenderObject树生成新的UI绘制信息,交给renderView,并生成一个Scene给SingletonFlutterWindow,而后GPU去渲染新的界面
硬件每次发出VSync信号处理流程以下
关于图片中的一些补充
这个方法最重要就是调用window.scheduleFrame()方法,从而调用platformDispatcher.scheduleFrame()方法,去通知engine层须要绘制。engine会根据状况尽快地调用platformDispatcher的onDrawFrame方法。
顺便一提的是,当咱们开发过程当中调用了setState()方法的时候,会调用BuildOwner的scheduleBuildFor方法,scheduleBuildFor方法中会调用onBuildScheduled这个callback,onBuildScheduled是由WigetsBinding这个mixin中传入的。对应着WigetsBinding的_handleBuildScheduled这个方法。
_handleBuildScheduled这个方法最终也是会调用window.scheduleFrame()通知engine更新界面。
runApp这个方法总的来讲就是作了如下的事情