终于放假啦,不用一直写业务代码了,也终于有点时间可以整理整理笔记啦。
我在这里先给大家拜个早年,恭祝大家新春快乐,吉祥安康啦!
FlutterFramework在Flutter层的项目入口是main
函数,默认生成的函数如下
void main() {
runApp(MyApp());
}
runApp
是一个顶级函数,接受一个Widget
作为rootWidget,这中间发生了什么嘞?
下文以图片、源码和文本解析的方式辅助学习。由于内容较长,需要分为几个部分学习,并且序列图、记录点和实际运行顺序有出入,下文排序主要是为了能够由浅入深的铺开runApp过程中的知识点,帮助更好的理解。
main
函数,调用runApp(Widget)
函数///同main函数,runApp函数也是一个顶级函数
void main() {
runApp(MyApp());
}
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
ensureInitialized
函数会创建一个WidgetsFlutterBinding
的单例WidgetsBinding.instance
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
///确认WidgetsBinding.instance是否创建成功,flutter framework工作是是否完成
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
WidgetsFlutterBinding
通过mixIn语法继承了7个BindingBase
子类,完成整个FlutterFramework层次的系统功能初始化。mixIn语法可参考我的这篇文章HelloDart-MixIn,土话记录多继承机制。abstract class BindingBase {
///会按照WidgetsFlutterBinding集成顺序,以此调用每个WidgetsFlutterBinding子类的
///initInstances和initServiceExtensions初始化函数。
BindingBase() {
developer.Timeline.startSync('Framework initialization');
assert(!_debugInitialized);
initInstances();
assert(_debugInitialized);
assert(!_debugServiceExtensionsRegistered);
initServiceExtensions();
assert(_debugServiceExtensionsRegistered);
developer.postEvent('Flutter.FrameworkInitialization', {});
developer.Timeline.finishSync();
}
}
initInstances
和initServiceExtensions
该部分比较复杂,这里先不学习了。简单介绍一下BindingBase
系列子类的作用,下列内容我也是看注释的,如有错误烦请指出
WidgetsFlutterBinding
:将FlutterFramework绑定到FlutterEngine上面GestureBinding
:绑定手势系统。ServicesBinding
:主要作用与defaultBinaryMessenger
有关,用于和native通讯相关。SchedulerBinding
:改类也继承了ServicesBinding,主要用于调度帧渲染相关事件。PaintingBinding
:和painting库绑定SemanticsBinding
:将语义层和FlutterEngine绑定起来。RendererBinding
:将渲染树与FlutterEngine绑定起来。WidgetsBinding
:将Widget层与FlutterEngine绑定起来。初始化完WidgetsFlutterBinding.instance
及一堆系统Binding之后,便开始下一步操作了。
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
这里使用级联语法分别调用了scheduleAttachRootWidget(Widget)
和scheduleWarmUpFrame
函数,具体过程见下文
scheduleAttachRootWidget(app)
:通过级联的方式,生成了WidgetsFlutterBinding.instance静态实例并初始化一干系统功能之后,调用WidgetsFlutterBinding.scheduleAttachRootWidget(Widget root)
函数。void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
attachRootWidget(Widget)
:这里异步调用WidgetsBinding.attachRootWidget(Widget rootWidget)
函数,只为了尽快显示Flutter项目的UI画面。 void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
scheduleWarmUpFrame()
:在上面第二点中,异步调用attachRootWidget
函数,只为了尽快调用该函数,去显示一个帧画面。这个函数的详细流程按下不表,等以后再学习。 /// Schedule a frame to run as soon as possible, rather than waiting for
/// the engine to request a frame in response to a system "Vsync" signal.
void scheduleWarmUpFrame() {
...
}
RenderObjectToWidgetAdapter
:接着第2点,attachRootWidget函数作用就是将根Widget、根Element与根RenderObject三个跟对象绑定起来,并将唯一的BuildOwner对象引用作为根对象的持有对象,通过继承关系层层传递。看代码///伪代码
class WidgetsBinding ...{
void attachRootWidget(Widget rootWidget) {
//创建一个RenderObjectToWidgetAdapter对象,泛型T是RenderBox类型,
_renderViewElement = RenderObjectToWidgetAdapter(
container: renderView,
debugShortDescription: '[root]',//renderView[注释1]是连接到物理设备输出层的渲染树对象
child: rootWidget, //根Widget树
).attachToRenderTree(buildOwner, renderViewElement);
}
}
class RenderObjectToWidgetAdapter extends RenderObjectWidget {
/// Creates a bridge from a [RenderObject] to an [Element] tree.
///
/// Used by [WidgetsBinding] to attach the root widget to the [RenderView].
RenderObjectToWidgetAdapter({
this.child,
this.container,
this.debugShortDescription,
}) : super(key: GlobalObjectKey(container));
/// The widget below this widget in the tree.
final Widget child;
/// The [RenderObject] that is the parent of the [Element] created by this widget.
final RenderObjectWithChildMixin container;
@override
RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this);
@override
RenderObjectWithChildMixin createRenderObject(BuildContext context) => container;
@override
void updateRenderObject(BuildContext context, RenderObject renderObject) { }
///
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;
}
}
attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement element ])
:**这里面关于element
的创建先忽略,在步骤3中学习。**该部分源码在第四点中,我们可以看到RenderObjectToWidgetAdapter
会创建一个RenderObjectToWidgetElement
对象,作为WidgetsBinding
中的_renderViewElement
对象。该_renderViewElement
对象也就是整个Element树中的跟对象,其持有根Widget、根RenderView与BuildOwner对象。过程三主要分析RenderObjectToWidgetAdapter.attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement
函数,期间还有一些BaseBinding内容掺杂进来,比较复杂。
BuildOnwer.lockState(fn)
:
///该函数中的_debugStateLocked 布尔值,每次调用该函数_debugStateLockLevel都会+1,
///callback运行完之后减1,如果在_debugStateLocked等于true期间调用setState就会抛出异常。
void lockState(void callback()) {
assert(callback != null);
assert(_debugStateLockLevel >= 0);
assert(() {
_debugStateLockLevel += 1;
return true;
}());
try {
callback();
} finally {
assert(() {
_debugStateLockLevel -= 1;
return true;
}());
}
assert(_debugStateLockLevel >= 0);
}
RenderObjectToWidgetAdapter.createElement()
:会创建一个RenderObjectToWidgetElement
对象。
这里先不去细看其众多父类中的属性和操作
element.assignOwner(owner)
:将owner:BuildOnwer
赋值给element
,该owner:BuildOnwer
是整个Element树的统一管理者。
element.mount(null, null)
:上图忽略了BuildOwner.buildScope(Element context, [ VoidCallback callback ])
函数了,该函数作用在于将一个Element添加进去构建域中,并调用VoidCallback
函数作为回调。
这里要着重看下element对象一众父类中的mount函数了
owner.buildScope(element, () {
element.mount(null, null);
});
class RenderObjectToWidgetElement ...{
@override
void mount(Element parent, dynamic newSlot) {
assert(parent == null);
super.mount(parent, newSlot);
//这里的child暂时为null,忽略rebuild函数
_rebuild();
}
}
abstract class RootRenderObjectElement extends RenderObjectElement {
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
}
}
///RenderObjectElement类中,最重要的属性,_renderObject
///是该根Element的RenderObject对象,该RenderObject类存储
///了Element的位置信息,Skia是一个2D渲染框架,基于笛卡尔坐标轴
///RenderObject也实现了基本的渲染功能。
abstract class RenderObjectElement extends Element {
/// The underlying [RenderObject] for this element.
@override
RenderObject get renderObject => _renderObject;
RenderObject _renderObject;
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
//这个回到步骤二中的RenderObjectToWidgetAdapter类,RendererBinding类初始化之后有个PipelineOwner
//对象,PipelineOwner对象中有个rootNode对象,就是该_renderObject了
_renderObject = widget.createRenderObject(this);
//这里newSlot等于null,忽略
attachRenderObject(newSlot);
//将dirty置为false,
_dirty = false;
}
}
class Element ...{
@mustCallSuper
void mount(Element parent, dynamic newSlot) {
//一顿赋值
_parent = parent;
_slot = newSlot;
_depth = _parent != null ? _parent.depth + 1 : 1;
_active = true;
if (parent != null) // Only assign ownership if the parent is non-null
_owner = parent.owner;
if (widget.key is GlobalKey) {
final GlobalKey key = widget.key;
key._register(this);
}
_updateInheritance();
assert(() {
_debugLifecycleState = _ElementLifecycle.active;
return true;
}());
}
}
mount(Element parent, dynamic newSlot)
挂载函数在于将Element挂载到Element树上去,如果有parent属性就赋值,挂载之后Element的状态变为active。
SchedulerBinding.instance.ensureVisualUpdate()
:该函数最终调用的WidgetsFlutterBinding.handleDrawFrame()
函数,该部分知识在Flutter笔记——runApp发生了什么(源码学习)文章中分析学习。
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
SchedulerBinding.scheduleFrame()
:接着便是调用window.scheduleFrame()
函数了,这是一个native函数,纯FlutterFramework部分线索就断了。
void scheduleFrame() {
if (_hasScheduledFrame || !_framesEnabled)
return;
assert(() {
if (debugPrintScheduleFrameStacks)
debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
return true;
}());
ensureFrameCallbacksRegistered();
window.scheduleFrame();
_hasScheduledFrame = true;
}
main
函数。runApp(Widget)
函数传入一个Widget作为根Widget。Widget
只是一个配置类,不是实际的UI元素。runApp
通过WidgetsFlutterBinding
mixIn继承一众父类进行初始化。RendererBinding
父类中的renderView
对象,是实际的渲染对象。RenderObjectToWidgetAdapter
类,生成一个RenderObjectToWidgetElement
类型的Element作为根Element,并让Widget、renderView和BuildOwner和根Element产生关系。SchedulerBinding.instance.ensureVisualUpdate()
函数,等待下一帧渲染。scheduleAttachRootWidget
是一个耗时操作,异步运行。runApp会优先调用scheduleWarmUpFrame()
渲染预热帧。上述文章是笔者通过对Flutter1.12版本源码进行学习的总结,如有错漏,还烦请指出纠正,十分感谢。
另外本文只是runApp的源码进行了跟踪学习,Flutter到底是如何渲染到Native设备、还有BaseBinding系列子类作用等知识有待继续学习,而渲染调用的WidgetsFlutterBinding.handleDrawFrame()
函数部分知识在Flutter笔记——runApp发生了什么(源码学习)文章中分析学习哈。