先上代码:
void main() => runApp(MyApp());
//widgets/binding.dart
//1
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()//1-1
..scheduleAttachRootWidget(app)//1-2
..scheduleWarmUpFrame();//1-3
}
//widgets/binding.dart
//2
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
//foundation/binding.dart
//WidgetsFlutterBinding只有默认构造函数,所以实际执行的是父类BindingBase的构造器
//3
BindingBase() {
initInstances();
initServiceExtensions();
developer.postEvent('Flutter.FrameworkInitialization', <String, String>{});
}
//widgets/binding.dart
//4
@protected
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
//widgets/binding.dart
//5
void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement<RenderBox>);
}
//widgets/binding.dart
//6
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;
}
//framework.dart
//7
void buildScope(Element context, [ VoidCallback callback ]) {
if (callback == null && _dirtyElements.isEmpty)
return;
try {
_scheduledFlushDirtyElements = true;
if (callback != null) {
_dirtyElementsNeedsResorting = false;
callback();
}
_dirtyElements.sort(Element._sort);
_dirtyElementsNeedsResorting = false;
int dirtyCount = _dirtyElements.length;
int index = 0;
while (index < dirtyCount) {
_dirtyElements[index].rebuild();
index += 1;
if (dirtyCount < _dirtyElements.length || _dirtyElementsNeedsResorting) {
_dirtyElements.sort(Element._sort);
_dirtyElementsNeedsResorting = false;
dirtyCount = _dirtyElements.length;
while (index > 0 && _dirtyElements[index - 1].dirty) {
index -= 1;
}
}
}
} finally {
for (final Element element in _dirtyElements) {
assert(element._inDirtyList);
element._inDirtyList = false;
}
_dirtyElements.clear();
_scheduledFlushDirtyElements = false;
_dirtyElementsNeedsResorting = null;
}
}
//framework.dart
//8
void markNeedsBuild() {
if (!_active)
return;
if (dirty)
return;
_dirty = true;
owner.scheduleBuildFor(this);
}
//framework.dart
//9
void scheduleBuildFor(Element element) {
if (element._inDirtyList) {
_dirtyElementsNeedsResorting = true;
return;
}
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled();
}
_dirtyElements.add(element);
element._inDirtyList = true;
}
//scheduler/binding.dart
//10
void scheduleWarmUpFrame() {
if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle)
return;
_warmUpFrame = true;
Timeline.startSync('Warm-up frame');
final bool hadScheduledFrame = _hasScheduledFrame;
// We use timers here to ensure that microtasks flush in between.
Timer.run(() {
handleBeginFrame(null);
});
Timer.run(() {
handleDrawFrame();
resetEpoch();
_warmUpFrame = false;
if (hadScheduledFrame)
scheduleFrame();
});
// Lock events so touch events etc don't insert themselves until the
// scheduled frame has finished.
lockEvents(() async {
await endOfFrame;
Timeline.finishSync();
});
}
解释每个方法的作用
-
runApp()
这个方法是我们Flutter程序的入口
-
ensureInitialized()
这个方法执行flutter的一些初始化工作
在这个方法里,第一次初始化WidgetsBinding.instance肯定是空的,所以执行了WidgetsBinding的构造器,而WidgetsBinding是默认的构造器,所以我们看它的父类BindingBase的构造器
-
BindingBase()
在这里做了一些系统服务的初始化工作,详细的请自己去看代码,这里略过。这时候注释1-1就执行完了。
-
attachRootWidget(注释1里的scheduleAttachRootWidget()调用了该方法)
该方法把我们传入到runApp方法里的参数作为child挂载到rootWidget上
这里方法里有个类叫做RenderObjectToWidgetAdapter,但是不要被它的名字迷惑了,实际这是一个RenderObjectWidget的子类,而RenderObjectToWidgetAdapter这个类很重要,这个类相当于Android里的DecorView,也是rootWidget
-
attachToRenderTree()
该方法创建了RootElement和RootRenderObject。
在第一次运行该方法的时候,element是null,所以会进入if这个分支里,这个方法里的createElement()方法创建了RenderObjectToWidgetAdapter对应的RootElement,然后element.assignOwner(owner)这句代码保存了BuildOwner这个引用(这个BuildOwner只有一个实例,是在WidgetsBinding的initInstances()方法里创建的,这个BuildOwner用来管理Element),然后执行owner.buildScope方法后执行SchedulerBinding.instance.ensureVisualUpdate()方法,最终会执行到window的scheduleFrame方法通知Engine下次 vsync 信号回调时,完成这些dirty元素的更新(Element初始化后_dirty默认为true)
-
owner.buildScope
该方法调用element的mount方法挂载element并调用_dirtyElements的rebuild方法。
这个方法首先调用我们传入的callback方法,而我们传入的callback会执行element.mount(null, null),这个mount方法最终会调用到RenderObjectElement的mount方法,在这个方法里有一句代码是widget.createRenderObject(this),该方法创建了RenderObject。然后下面还有一句代码attachRenderObject(newSlot),该方法将刚才生成的RenderObject挂载到了RenderObject树中的某个slot,因为它是RenderObjectElement所以其实这个刚生成的RenderObject就作为了RenderObject树的根节点。然后我们继续看buildScope这个方法做了什么,在这个方法里,会先调用_dirtyElements.sort(Element._sort)对Element排序,因为如果先build child的话,在build parent的时候会再执行一遍child的build方法,所以这里做一次排序,然后把标记为dirty的Element挨个执行rebuild方法,但是,下面还有一个if (dirtyCount < _dirtyElements.length || _dirtyElementsNeedsResorting)判断,这是因为在rebuild的时候,可能有新的dirty的element加入到_dirtyElements列表里,所以我们要对_dirtyElements再次排序,并找到列表最前面不是dirty的element的index(在第一次执行dirty的element的rebuild方法后这个element就不是dirty的了),然后从这个index再次往后执行element的rebuild方法。
-
attachToRenderTree()剩余代码
然后我们回到该方法,当有了RootElement,再调用该方法时会进入该方法的else分支,else里有这样两句代码
element._newWidget = this; element.markNeedsBuild();
也就是说,如果执行该方法时已经有了RootElement,RenderObjectToWidgetAdapter把自己赋值给自己对应的element的_newWidget属性,然后标记这个element为dirty。
-
markNeedsBuild()
这个方法会调用owner.scheduleBuildFor(this)方法,通知owner刷新页面
-
scheduleBuildFor()
该方法里会先执行onBuildScheduled()方法,再把当前element添加到_dirtyElements列表里,而onBuildScheduled这个方法是WidgetsBinding的initInstances方法里赋值的,所以这个方法实际上是WidgetsBinding类的_handleBuildScheduled方法,而这个方法会调用ensureVisualUpdate并最终会执行到SchedulerBinding类的scheduleFrame方法
-
scheduleFrame()
void scheduleFrame() {
if (_hasScheduledFrame || !framesEnabled)
return;
ensureFrameCallbacksRegistered();
window.scheduleFrame();
_hasScheduledFrame = true;
}
在这个方法里,会执行window.scheduleFrame()
方法,该方法是Dart Engine
底层的一个方法,它会触发 vsync
信号,以便在下次 vsync
信号回调时,完成这些dirty
元素的更新。
我下面画了这么个流程,把最上面单独的方法串联了起来
runApp 入口
-> WidgetsFlutterBinding.scheduleAttachRootWidget
-> WidgetsFlutterBinding.attachRootWidget
创建了RenderObjectToWidgetAdapter这个RootWidget,然后把我们传入的app作为它的child
-> RenderObjectToWidgetAdapter.attachToRenderTree
该方法有2个分支:
1. 系统初始化时element参数为null,所以方法中通过createElement()创建了Flutter的第一个Element(该element是RenderObjectToWidgetAdapter对应的RenderObjectToWidgetElement),然后调用该element的mount方法和_rebuild方法
1.1 RenderObjectToWidgetElement.mount方法和RenderObjectToWidgetElement._rebuild方法
1.1.1 -> RenderObjectToWidgetElement.mount
该方法调用了当前element父节点(RootRenderObjectElement)的mount方法和它自己的_rebuild()方法
-> RootRenderObjectElement.mount
-> RenderObjectElement.mount
该方法创建了Flutter的第一个RenderObject,该方法内部会调用自己的attachRenderObject方法
-> RenderObjectElement.attachRenderObject
因为上面创建的是Flutter的第一个RenderObject,所以该方法内部其实什么都没做。(如果不是第一个节点(根节点)的话,会找到当前RenderObjectElement的上一级的RenderObjectElement节点,然后把当前RenderObjectElement插到上个节点中,并委托上个节点设置自己的parentData属性)
1.1.2 -> RenderObjectToWidgetElement._rebuild
该方法内部调用updateChild(Element child, Widget newWidget, dynamic newSlot)方法,该方法根据不同条件来决定是删除自身还是更新自身
1.2 完成上面的1.1.1和1.1.2的操作后,通过owner.buildScope方法来调用_dirtyElements列表中element的rebuild()方法,然后调用SchedulerBinding.instance.ensureVisualUpdate(),最终会调用window.scheduleFrame()通知系统刷新第一帧;
2. 当element不为null时的调用处没找到;当element不为null时,调用该element的markNeedsBuild()方法,该方法内部会调用owner.scheduleBuildFor(this)
-> BuildOwner.scheduleBuildFor
1. 先执行onBuildScheduled()方法,该方法是WidgetsBinding.initInstances()方法中设置的,该方法的实现是WidgetsBinding._handleBuildScheduled()
2. 把scheduleBuildFor方法中的参数添加到_dirtyElements集合中
-> WidgetsBinding._handleBuildScheduled
该方法调用SchedulerBinding.instance.ensureVisualUpdate(),最终会调用window.scheduleFrame()通知系统刷新下一帧;同上面的1.2最后的调用一样
-> RenderObjectToWidgetAdapter.scheduleWarmUpFrame
这个方法我没仔细看,大概是通知系统开始绘制第一帧的意思
总结
在runApp
方法里,在调用WidgetsFlutterBinding.scheduleAttachRootWidget
这个方法时,我们创建了RenderObjectToWidgetAdapter
这个RootWidget
,然后把我们传入的app
作为它的child
,再然后RenderObjectToWidgetAdapter
调用了它自己的attachToRenderTree
方法,该方法中通过createElement()
创建了RootElement
,然后这个element
调用它的mount
方法创建了RootRenderObject
,然后WidgetsFlutterBinding.scheduleAttachRootWidget
调用SchedulerBinding.instance.ensureVisualUpdate()
刷新第一帧。
疑问
我看到这里有个地方不清楚,有知道的小伙伴帮我解答一下,就是attachToRenderTree这个方法的什么时候会进入else方法快,我查了一下没找到哪里可以进入这个else,请知道的小伙伴指点一下,谢谢