首帧渲染

Catalogue   

关键类

Widget关键类

Widget是对Element的配置或描述。Widget的子类主要有3类:

  • RenderObjectWidget的子类,可以进行Layout、Paint等逻辑

    • SingleChildRenderObjectWidget(单子节点容器)
    • LeafRenderObjectWidget(叶子节点)
    • MultiChildRenderObjectWidget(多叶子节点容器)
  • StatelessWidget和StatefulWidget,自身不具备绘制能力,用来组织和配置RenderObjectWidget类型的Widget

  • ProxyWidget,具体又分为ParentDataWidget和InheritedWidget,为其子节点提供额外的数据

Element关键类

每个Element都有一个对应的Widget,其主要工作都处于渲染流水线的构建阶段(build)。

RenderObject关键类

RenderView是整个Render Tree的根节点,负责布局(layout)、绘制(paint)。

根节点构建流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}

void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}

void attachRootWidget(Widget rootWidget) {
final bool isBootstrapFrame = renderViewElement == null;
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
if (isBootstrapFrame) {
SchedulerBinding.instance.ensureVisualUpdate();
}
}


RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {
if (element == null) {//首帧构建
owner.lockState(() {
element = createElement();//创建Widget对应的Element
assert(element != null);
element!.assignOwner(owner);//绑定BuildOwner
});
owner.buildScope(element!, () {//开始子节点的解析与挂载
element!.mount(null, null);
});
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element!;
}

//binding.dart
@override
void mount(Element? parent, Object? newSlot) {
assert(parent == null);
super.mount(parent, newSlot);
_rebuild();//开始构建
assert(_child != null);
}

void _rebuild() {
try {
_child = updateChild(_child, (widget as RenderObjectToWidgetAdapter<T>).child, _rootChildSlot);//build整个tree
} catch (exception, stack) {
final FlutterErrorDetails details = FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'widgets library',
context: ErrorDescription('attaching to the render tree'),
);
FlutterError.reportError(details);
final Widget error = ErrorWidget.builder(details);
_child = updateChild(null, error, _rootChildSlot);
}
}



//framework.dart
@override
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
_renderObject = (widget as RenderObjectWidget).createRenderObject(this);//创建Widget对应的RenderObject
attachRenderObject(newSlot);
super.performRebuild(); // clears the "dirty" flag
}


Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
if (newWidget == null) {//如果新的Widget为空,则销毁child
if (child != null) {
deactivateChild(child);
}
return null;
}
final Element newChild;
if (child != null) {
bool hasSameSuperclass = true;
if (hasSameSuperclass && child.widget == newWidget) {
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
newChild = child;
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {//检查新旧Widget是否可以更新,默认比较类型和key
if (child.slot != newSlot) {
updateSlotForChild(child, newSlot);
}
child.update(newWidget);
newChild = child;
} else {
deactivateChild(child);
newChild = inflateWidget(newWidget, newSlot);
}
} else {
newChild = inflateWidget(newWidget, newSlot);
}
return newChild;
}


Element inflateWidget(Widget newWidget, Object? newSlot) {
final Key? key = newWidget.key;
if (key is GlobalKey) {//globalkey的处理
final Element? newChild = _retakeInactiveElement(key, newWidget);
if (newChild != null) {
newChild._activateWithParent(this, newSlot);
final Element? updatedChild = updateChild(newChild, newWidget, newSlot);
return updatedChild!;
}
}
final Element newChild = newWidget.createElement();//创建新的Element
newChild.mount(this, newSlot);
return newChild;
}