使用Flutter开发项目时,只需要调用入口函数main(MyApp()),Flutter项目就运行起来了;之后进行了哪些操作呢?弄清楚这个问题对提高对Flutter中widget,element,renderObject 的理解非常有帮助
Element持有Widget,可能持有RenderObject 例如:RenderObjectWidget及其子类
Widget是Element的配置信息,用来构建Element树,和渲染树
Element的关键方法 mount,updateChild
入口函数
void main() => runApp(MyApp());
//实际调用
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()//1
..attachRootWidget(app)//2
..scheduleWarmUpFrame();//3
}
注释1 返回WidgetsBinding单例对象 代码如下:
//WidgetsFlutterBinding
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
//BindingBase
//构造方法
BindingBase() {
...
initInstances();
...
}
首先WidgetsFlutterBinding 继承了BindingBase 并混入(dart中混入及其理解这里不做介绍,可自行百度) SchedulerBinding,RendererBinding,WidgetsBinding等这几个类,并分别对其初始化作为静态对象进行持有 例如:
//SchedulerBinding类
static SchedulerBinding get instance => _instance;
static SchedulerBinding _instance;
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onBeginFrame = _handleBeginFrame;
window.onDrawFrame = _handleDrawFrame;
...
}
//RendererBinding类
@override
void initInstances() {
super.initInstances();
_instance = this;
_pipelineOwner = PipelineOwner(//创建pipellineOwner对象
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
window
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
initRenderView();//创建renderView
_handleSemanticsEnabledChanged();
assert(renderView != null);
addPersistentFrameCallback(_handlePersistentFrameCallback);//添加渲染回调监听
_mouseTracker = _createMouseTracker();
}
注释2 创建根widget RenderObjectToWidgetAdapter,并创建渲染树
//WidgetsBinding类
void attachRootWidget(Widget rootWidget) {
_renderViewElement = RenderObjectToWidgetAdapter(//2-1
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement);//2-2
}
注释2-1创建RenderObjectToWidgetAdapter对象
注释2-2 attachToRenderTree(buildOwner, renderViewElement)返回Element对象 代码如下:
//RenderObjectToWidgetAdapter类 继承 RenderObjectWidget
RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement element ]) {
if (element == null) {
owner.lockState(() {//2-2-1
element = createElement();
assert(element != null);
element.assignOwner(owner);
});
owner.buildScope(element, () {//2-2-2
element.mount(null, null);
});
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element;
}
注释2-2-1 通过owner对象创建Element,调用assignOwner(owner)方法 element持有owner对象
注释2-2-2 调用如下
void buildScope(Element context, [ VoidCallback callback ]) {
if (callback == null && _dirtyElements.isEmpty)
return;
...
try {
...
try {
callback();
} finally {
assert(() {
context._debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
assert(_debugCurrentBuildTarget == context);
_debugCurrentBuildTarget = debugPreviousBuildTarget;
_debugElementWasRebuilt(context);
return true;
}());
}
}
...
}
实际调用的是 element.mount(null, null) ;只是把函数作为参数传递给owner.buildScope而已
继续追踪 element的挂载方法mount
//RenderObjectToWidgetElement类
@override
void mount(Element parent, dynamic newSlot) {
assert(parent == null);
super.mount(parent, newSlot);
_rebuild();//1
}
//依次调用父类mount方法
//RootRenderObjectElement类
@override
void mount(Element parent, dynamic newSlot) {
// Root elements should never have parents.
assert(parent == null);
assert(newSlot == null);
super.mount(parent, newSlot);
}
//RenderObjectElement类
@override
void mount(Element parent, dynamic newSlot) {
super.mount(parent, newSlot);
_renderObject = widget.createRenderObject(this);//2
assert(() { _debugUpdateRenderObjectOwner(); return true; }());
assert(_slot == newSlot);
attachRenderObject(newSlot);//3
_dirty = false;
}
注释2 element通过持有的widget创建 渲染对象renderObject,恍然大悟的感觉
注释3 更惊喜 attachRenderObject 构建渲染对象关系,即维护渲染树
(备注:注释3的具体实现是获取上层的Element,维护渲染树关系,这里不做深入研究 )
注释1 在element执行挂载(注释2,注释3)后调用 代码如下:
//RenderObjectToWidgetElement类
void _rebuild() {
try {
_child = updateChild(_child, widget.child, _rootChildSlot);
assert(_child != null);
} catch (exception, stack) {
...
}
//Element类
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
...
if (newWidget == null) {
if (child != null)
deactivateChild(child);
return null;
}
if (child != null) {
...这一部分代码 虽然很重要,但是当前不研究
}
return inflateWidget(newWidget, newSlot);
}
//Element类
Element inflateWidget(Widget newWidget, dynamic newSlot) {
assert(newWidget != null);
...
final Element newChild = newWidget.createElement();//1-1
assert(() { _debugCheckForCycles(newChild); return true; }());
newChild.mount(this, newSlot);//1-2
assert(newChild._debugLifecycleState == _ElementLifecycle.active);
return newChild;
}
从代码可知调用顺序 _rebuild->updateChild->inflateWidget,注释1-1调用传入的子widget 创建相应的element 眼熟否? 接着执行 注释1-2 Element 类newChild 的mount方法 又开始挂载下一层Element ,
依次类推 构建整个树状的Element层级结构 和RenderObject层级结构(StatefulWidget和StatelessWidget对应的Element没有渲染对象renderObject)
注释3 调用scheduleWarmUpFrame方法
//SchedulerBinding类
void scheduleWarmUpFrame() {
...
// We use timers here to ensure that microtasks flush in between.
Timer.run(() {
assert(_warmUpFrame);
handleBeginFrame(null);//3-1
});
Timer.run(() {
assert(_warmUpFrame);
handleDrawFrame();//3-2
...
}
...
}
注释3-1 预处理界面更新 注释3-2处理渲染(这里笼统描述,和Flutter的渲染机制有关系) 继续追踪代码
//SchedulerBinding类
void handleDrawFrame() {
...
try {
...
for (FrameCallback callback in _persistentCallbacks)//1
_invokeFrameCallback(callback, _currentFrameTimeStamp);
// POST-FRAME CALLBACKS
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List localPostFrameCallbacks =
List.from(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp);
} finally {
...
}
}
void _invokeFrameCallback(FrameCallback callback, Duration timeStamp, [ StackTrace callbackStack ]) {
...
try {
callback(timeStamp);
} catch (exception, exceptionStack) {
...
}
}
}
final List _persistentCallbacks = [];
/// Adds a persistent frame callback.
///
/// Persistent callbacks are called after transient
/// (non-persistent) frame callbacks.
///
/// Does *not* request a new frame. Conceptually, persistent frame
/// callbacks are observers of "begin frame" events. Since they are
/// executed after the transient frame callbacks they can drive the
/// rendering pipeline.
///
/// Persistent frame callbacks cannot be unregistered. Once registered, they
/// are called for every frame for the lifetime of the application.
void addPersistentFrameCallback(FrameCallback callback) {//2
_persistentCallbacks.add(callback);
}
注释1 遍历了_persistentCallbacks容器,是一个List,存放的是FrameCallback 函数类型 ,_invokeFrameCallback方法实际就是执行 这个容器中的callback对象
然后 这个_persistentCallbacks容器中的FrameCallback 对象 是谁放入的呢? 即谁调用了 注释2 的函数 哪里调用的?
还记得本篇文字 开始位置提到的 RendererBinding类,看initInstances方法
//RendererBinding 类
@override
void initInstances() {
super.initInstances();
...
addPersistentFrameCallback(_handlePersistentFrameCallback);
...
}
原来在WidgetFlutterBinding初始化的时候 已经调用了addPersistentFrameCallback方法 添加了函数对象 ~小激动!
看下这个函数对象具体执行了什么操作
//RendererBinding类
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
}
/// Pump the rendering pipeline to generate a frame.
///
/// This method is called by [handleDrawFrame], which itself is called
/// automatically by the engine when it is time to lay out and paint a frame.
///...
@protected
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();//1
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();//2
renderView.compositeFrame(); // this sends the bits to the GPU //3
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
}
@override
void drawFrame() {
...
try {
if (renderViewElement != null)
buildOwner.buildScope(renderViewElement);//3
super.drawFrame();
buildOwner.finalizeTree();
} finally {
assert(() {
debugBuildingDirtyElements = false;
return true;
}());
}
...
}
实际上 先调用的是WidgetsBinding类drawFrame方法 然后再调用 其混入的RendererBinding类drawFrame方法,调用注释3 buildScope方法,
和 上文中 提到的 创建根widget RenderObjectToWidgetAdapter 调用attachToRenderTree 注释2-2-2 一样,只不过没有传入callback参数
遍历_dirtyElements 调用标记为dirt的element的 rebuild方法,最终调用widget的build,大功告成!
接着计算布局,进行绘制
pipelOwner是RenderBinding中生成并持有的对象,渲染树的owner
注释1 字面意思刷新布局 每个RenderObject及其子类都持有pipelLineOnwer对象
注释2 刷新绘制 注释3 把计算的显示信息发送给gpu进行渲染
这里不做深入研究