flutter_run_app_analyze
Flutter源码版本为1.12.13
用做简单的例子来讲,这个用户布局只有一个TextView
void main() => runApp(
Text("你好",
textDirection: TextDirection.ltr),
);
首先来看runApp()方法:
void run(Widgetr app){
WidgetsFultterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
- Step1.前置环境,主要是在WidgetsFultterBinding.ensureInitialized()
首先来看WidgetsFultterBinding的定义,这个类从右WidgetBinding往左GestureBinding进行初始化,下面只罗列关键的一些初始化
class WidgetFlutterBinding extends BindingBase with GestureBinding, ServiceBinding, ScheduleBinding, PaintingBinding, SemanticsBinding, RenderBinding, WidgetBinding{
...
}
@WidgetBinding
mixin WidgetBinding{
BuildOwner _buildOwner;
void initInstances(){
_buildOwner = BuildOwner();
}
}
@RenderBinding
mixin RenderBinding{
PipelineOwner _pipelineOwner;
void initInstance(){
_pipelineOwner = PipelineOwner(...);
initRenderView();
addPersistentFrameCallback(_handlePersistentFrameCallback);
}
void initRenerView(){
render = Render(...);
render.prepareInitialFrame();
}
set renderView(RenderView value){
_pipelineOwner.rootNode = value;
}
}
@PipelineOwner
class PipelineOnwer{
AbstractNode _rootNode;
set rootNode(AbstractNode value){
_rootNode?.attach(this);
}
}
@RendView
void prepareInitialFrame(){
scheduleInitialLayout();
sceduleInitialPaint(_updateMatricesAndCreateNewRootLayer());
}
void addPersistentFrameCallback(FrameCallback callback){
_persistentCallbacks.add(callback);
}
void _handlePersistentFrameCallback(Duration timeStamp){
drawFrame();
}
至此,需要的前置工作都完成了,生成了一个PipelineOwner与RenderView并且互相持有。创建了一个BuildOnwer,在_persistentCallbacks中注册了回调函数_handlePersistentFrameCallback(),最终调用到drawFrame();
- Step2 . scheduleAttachRootWidget(Widget)@WidgetBinding
void scheduleAttachRootWidget(Widget rootWidget){
Timer.run((){
attachRootWidget(rootWidget);
});
}
Element get renderViewElement => _renerViewElement;
Element _renderViewElement;
void attachRootWidget(Widget rootWidget){
//这里先生成一个RenderObjectToWidgetAdapter<Render>对象,再调用attachToRenerTree()生成一个Element,该Element为根
_renderViewElement = RenderObjectToWidgetAdapter<Render>(
container: renderView,
chhild:rootWidget,
).attachToRenderTree(buildOwner, renderViewElement);
}
@RenderObjectToWidgetAdapter<Render>
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget{
//就是用户自定义的Widget
final Widget child;
//就是RenderView对象
final RenderObjectWithChildMixin<T> container;
RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this);
RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container;
//重点
RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner,[RenderObjectToWidgetElement<T> element]){
if(element == null){
//命中,入参element此时为null
//lockState()@BuildOwner会调用callback
owner.lockState((){
//可以看到,element会RenderObjectToWidgetElement<RenderBox>对象,并且内部的widget为this,即RenderObjectToWidgetAdapter<RenderBox>
element = createElement();
element.assignOwner(owner);
});
owner.buildScope(element, (){
//调用mount()函数入参均为0,这个方法在第三步讨论
element.mount(null,null);
});
}else{
...
}
return element
}
}
- Step3. mount(null,null)@RenderObjectToWidgetElement<RenderBox>
@RenderObjectToWidgetElement
void mount(Element parent, dynamic newSlot){
super.mount(parent,new Slot);
_rebuild();
}
@RenderObjectElement
class RenderObjectElement{
RenderObject _renderObject;
void mount(Element parent, dynamic newSlot){
//对于REnderObjectToWidgetElement,widget就是RenderObjectToWidgetAdapter
//于是返回的_renderObject就是RenderView
_renderObject = widget.createRenderObject(this);
attachRenderObject(newSlot);
}
void attachRenderObject(dynamic newSlot){
//重点,是在这里进行生成RenderObject树的
//_findAncestoreRenderObjectElement是向上寻找最近的RenderObjectElement,只有该Element才有RenderObject,
//找到后将其作为当前RenderObject的parent,属于递归
//在这里是根Element,所以不会执行
_ancestoreRenderObjectElement = _findAncestoreRenderObjectElement();
//由子类实现,一般来说是把自身挂到最近的父RenderObject上,递归生成RenderObject树
_ancestoreREnderObjectElement?.insertChildREnderObject(renderObject, newSlot);
}
RenderObjectElement _findAncestoreRenderObjectElement(){
Element ancestore = _parent;
while(ancestore!=null && ancestore is! RenderObjectElement){
ancestore = ancestore._parent;
}
return ancestore;
}
}
//也是很关键,在这里方法里会进行递归,构造Widget树,Element树,RenderObject树
void _rebuild(){
//在这里,_child为null,widget为RenderObjectToWidgetAdapter<BoxRender>,
//于是widget.chil即为我们自定义的Widget,在这里就是Text()
_child = updateChild(_child, widget.child, _rootChildSlot);
}
Element updateChild(Element child, Widget newWidget, dynamic newSlot){
//因为child为null,于是直接是最后一步
return inflateWidget(newWidget, newSlot);
}
Element inflateWidget(Widget widget, dynamic newSlot){
//创建子,即Text的Element
//由具体的子类实现
final Element newChild=newWidget.createElement();
//该方法会递归构造Widget树,Element树,RenderObject树
//该方法由具体的子类实现
newChild.mount(this, newSlot);
//返回子的Element,并且挂载在当前RenderObjectToWidgetElement的_child上
return newChild;
}
于是,我们拥有了一个RenderView和Pipeline对象,互相持有。
一个RenderObjectToWidgetElement<BoxRender>,其_child为Text(自己实现的Widget).createElement()对象,其widget成员变量为RenderObjectToWidgetAdapter<BoxREnder>,其_renderObject变量为RenderView
一个RenderObjectToWidgetAdapter<BoxRender对象>,其child为用户自定义的Widget,container为RenderView。该对象如其名,Adapter,属于一个桥接的功能。
- Step4 三颗树的构造。
我们的定义的子类的Text,因此要去Text的源码里面看了,之前分析到newWidget.createElement()/newChild.mount(this,newSlot).【newWidget为Text,this指向RenderObjectToWidgetElement,后面可以知道newChild为newWidget调用crateElement()创建的StatelessElement对象】
首先来看Text类的继承结构
Text -> StatelessWidget -> Widget
//Text没有重写createElement(),该方法在StatelessWidget实现
@StatelessWidget
abstract class StatelessWidget extends Widget{
//执行完之后,Text创建了一个StatelessElement,其内部的widget即为Text本身,
//并且将该StatelessElement作为RenderObjectToWidgetElement<BoxRender>的_child进行挂载
StatelessElement createElement() => StatelessElement(this);
}
//StatelessElement继承自ComponentElement
@ComponentElement
abstract class ComponentElement extends Element{
//在这里parent为根RenderObjectToWidgetElement
void mount(Element parent, dynamic newSlot){
//super.mount()将RenderObjectToWidgetElement最为parent进行挂载
//将其owner作为本身的owner即BuildOwner,同时更新树的深度
super.mount(parent, newSlot);
_firstBuild();
}
void _firstBuild(){
rebuild();
}
@Element
void rebuild(){
...
performRebuild();
}
@ComponeneElement
void performRebuild(){
Widget build=build();
//这里开始递归调用了,同时_child为null,会执行inflateWidget(),
//已经分析过了,在递归挂载
//从下面分析可以知道,这里的build是RichText对象
_child=updateChild(_child, build, slot);
}
}
@StatelessElement
class StatelessElemet extends ComponentElement{
//widgt为Text
Widget() => widget.build(this);
}
@Text
class Text{
Widget build(BuildCOntext context){
Widget result=RichText(...);
return result;
}
}
//于是开始调用RichText的createElement()与 update@Element();
class RichText extends MultiChildRenderObjectWidget{
_MouseREgionElement createElement()=>_MouseRegionElement(this);
}
class _MouseRegionElement extends SigleChildRenderObjectElement(){
}
class SingleChildREnderObjectElement extends RenderObjectElement{
void mount(Element parent, dynamic newslot){
super.mount(parent, newSLot)
_child = updateChild(_child, widget.child, null);
}
}
class RenderObjectElement{
void mount(Element element, dynamic, newSlot){
super.mount(parent, newSlot);
_renderObject = widget.createRenderObject(this);
//在这里挂载RenderObject树
attachREnderObject(newSlot);
}
void attachRenderObject(dynamic newSlot){
//向上寻找最近的RenderObject,在这里就是REnderObjectToWidgetElement<BoxRender>
_ancestorRenderObjectElement=_findAncestoreRenderObjectElement();
//父类实现
_ancestorRenderObjectElement?.insertChildRenderObject(renderObject, newSLot);
}
@RenderBojectToWidgetElement
void insertChildRenderObject(RenderObject child, dynamic slot){
//将RichText创建的RenderObject挂载,最为child
renderObject.child = child;
}
//来看看挂载的RenderObject是什么
@TextRich
RenderParagaph createRenderObject(BuildContext context){
return RenderParagraph();
}
}
可以看到,在向下递归的过程中并且会将子节点的Element挂载到当前节点的Element生成Element树,如果当前节点Element为RenderObjectElement的子类,则在mount()的过程中,会将该节点的RenderObject挂载到父RenderObjectElement上,生成RenderObject树。
要注意的是Widget其实不会生成一颗树,在Widget的属性类别也没有【Widget child】这个属性,在代码中也找不到树的生成,从父Widget也无法直接访问到子Widget,从子Widget也无法访问到父Widget。那么我们说的Widget树到底是什么东西。
在Flutter中,一般树特指Element树,因为每个Element都持有其对应的Widget,并且可以根据Element树生成对应的RenderObject树。
- Step5
到此,我们在RenderObjectToWidgetElement中就构造好了Element树,RenderObject树,分别对应_child@RenderObjectToWidgetElement, _renderObject@RenderObjectToWidgetElement。
下面就开始进行渲染的过程了
- Setp6 渲染
下面要分析的是scheduleWarmUpFrame()函数【runApp()】
@ScheduleBinding
void scheduleWarmUpFrame(){
Timer.run((){
//不用关注
handleBeginFrame(null);
});
Timer.run((){
//重点
handleDrawFrame();
});
//这里就是调用engine进行绘制
//scheduleFrame()@window 属于engine的native方法
scheduleFrame();
}
void handleDrawFrame(){
//设定目前正在进行persistentCallbacks状态
_schedulerPhase = SchedulePhase.phersistentCallbacks;
//最上面分析过,最重要的一个callback在RenderBinding构造的时候添加了
//即doFrame()@RenderBinding
for(FrameCallback callback in _persistemtCallbacks){
_invokeFrameCallback(callback, _currentFrameTimeStamp);
}
...
}
@RenderBing
void drawFrame(){
//布局
pipelineOwner.flushLayout();
//合成
pipelineOwner.flushCompositingBits();
//绘制
pipelineOwner.flustPaint();
render.conpositeFrame();
pipelineOwner.flushSemantics();
}
void flushLayout(){
//scheduleInitialLayout()@RenderView的时候,RenderView将自己加入了PipelineOwner._nodesNeedingLayout
//遍历_nodesNeedingLayout
node._layoutWidhResize();
}
@RenderObject
void _layoutWidhResize(){
performLayout();
...
}
@RenderView
void performLayout(){
//对于RenderView来说,其Child就是在挂载RenderObject过程中挂载的,
//在这里是RenderParagraph
child.layout(BoxConstraints.tight(_size);
}
@RenderObject
void layout(Constraints constraints, {bool parentUserSize=false}){
RenderObject relayoutBoundary;
//this是RenderParagraph
relayoutBoundary = this
//根据子类具体实现,也是一般推荐子类只实现performLayout()的理由
performLayout();
}
@RenderParagraph
void performLayout(){
_layoutChildern(constraints);
_LayoutTextWithConstraints(constraints);
}
void _layoutChildren(){
RenderBox child = firstChild;
whild(child !=null){
//遍历执行子类的layout
child.layout(...);
child = childAfter(child);
}
}
在RenderObject树进行向下遍历Layout后,layout的操作就算完成了。
@PipelineOwner
voud flushPaint(){
PaintingContext.repaintCompositedChild(node);
}
@PaintingContext
static void repaintCompositedChild(RenderObject child, {bool debugAlsoPaintParent = false}){
//同理,这里的child是RenderView
_repaintCompositeChild(child);
}
static void _repaintCompositedChild(Render child){
child._paintWithContext(childContext, Offset.zero);
}
@RenderObject
void _paintWithContext(PaintingContext context, Offset offset){
paint(context, offset);
}
@RenderView
void paint(PaintingContext context, Offset offset){
//在这里,child就是RenderParagraph
context.paintChild(child,offset);
}
@PaintingContext
void paintChild(RenderObject child, Offset offset){
//在这里,child就是RenderParagraph,同上,会到底调用paint()
child._paintWithContext(child,offset);
}
@RenderParagraph
void paint(PaintingContext context, Offset offset){
//自身的绘制逻辑
while(child != null && childIndex < _textPainter.inlinePlaceholderBoxes.length){
//执行child,递归调用
context.paintChild(child.offset);
}
}
于是,会递归RenderObject树,进行perform(),再递归RenderObject,进行paint();
绘制完成后就可以调用engine进行绘制了。