flutter如何创建的视图树(WidgetTree),元素树(ElementTree)及渲染树(RenderingTree),又是如何更新视图绘制视图? 这个问题太大,刚开始一切又都是陌生的,理解起来千头万绪,因此先搞清这些树的根结点的身份是很是必要的。毫无疑问,这些根节点的创建紧密的与初始化过程关联,而肯定了这些根节点以后,遍历查找更新就相对清晰了,由于绘制视图无非也是对树的遍历查找更新操做。java
这部分就已经从引擎层进入到了dart层,须要了解的更多的是框架相关的机制,引擎目前用不到了。git
环境: flutter sdk v1.7.8+hotfix.4@stablegithub
先不要被Element
, RenderObjectElement
, RenderObject
, Widget
,RenderObjectWidget
诸多名称吓到。与安卓封装了显式的启动运行过程不一样,flutter有一个明确的runApp
, 这就是进行分析的方便入口。bash
须要先了解一下语言层面的一个多继承机制。虽然这里用了多继承这个名词,可是须要明确dart语言在语法上仍是单继承,也就是只能extends
一个类,其它接口分别再以with
串接。框架
与java不一样,dart没有interface
(准确的说是已移除)只有abstract
,abstract
的使用与java并没有二致。没有了interface
如何实现多接口对象的声明?dart用的是mixin
关键字,因此就方便理解而言,把mixin
看成interface
, on
看成extends
(只针对mixin
类)便可。与interface
不一样的是**mixin
声明的类是能够有方法实现体和成员对象的**。ide
class A extends B implements C, D, E {}
class B {}
interface C {}
interface D {}
interface E {}
复制代码
dart等同于:函数
class A extends B with C, D, E {}
class B {}
mixin C {}
mixin D {}
mixin E {}
复制代码
在以上例子中假如B,C,D都有doSomeThing
方法post
class A extends B with C, D {
@override
void doSomeThing() {
print("A");
super.doSomeThing();
}
}
class B {
@override
void doSomeThing() {
print("B");
}
}
mixin C on B {
@override
void doSomeThing() {
print("C");
super.doSomeThing();
}
}
mixin D on B {
@override
void doSomeThing() {
print("D");
super.doSomeThing();
}
}
void main() {
A().doSomeThing();
}
复制代码
那么当执行A.doSomeThing
后应该是哪一个调用顺序? 直接给结论:以with声明的反顺序继承 那么问题来了:若是没有C on B
会发生什么? 语言机制问题可参考这篇文章。ui
须要了解的第2个语法特性是串连调用,能够用..
操做符串连调用类的成员方法:this
class F {
String str;
String contact(String s) {
return str + s;
}
void assign(String s) {
str = s;
}
}
void mai() {
F f = F()..assign("hello")..contact(' world');
print(f.str);
}
复制代码
须要明确:用了..
操做符以后调用返回的就是类对象实例,再也不是方法的返回值。
有了以上基础(用到语言特性1: mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding
)就能够理清runApp
入口的调用序列:
runApp
WidgetsFlutterBinding.ensureInitialized
WidgetsFlutterBinding()
BindingBase()
WidgetsBinding.initInstances
RendererBinding.initInstances
SemanticsBinding.initInstances
PaintingBinding.initInstances
SchedulerBinding.initInstances
ServicesBinding.initInstances
GestureBinding.initInstances
BindingBase.initInstances
复制代码
这里包含了大量的数据初始化,用到一个找一个。 再看总体序列(widgets/binding.dart:786, 用到语言特性2):
runApp
WidgetsFlutterBinding.ensureInitialized
WidgetsBinding.attachRootWidget
WidgetsBinding.scheduleWarmUpFrame
复制代码
MyApp
实例被传给了WidgetsBinding.attachRootWidget
方法,因而分析其调用序列:
runApp
WidgetsBinding.attachRootWidget
RenderObjectToWidgetAdapter()
RenderObjectToWidgetAdapter.attachToRenderTree
RenderObjectToWidgetAdapter.createElement
RenderObjectToWidgetElement<RenderBox>.assignOwner
BuildOwner.buildScope
RenderObjectToWidgetElement<RenderBox>.mount
复制代码
须要注意RenderObjectToWidgetAdapter
是一个RenderObjectWidget
类型,它用构造函数child: rootWidget,
持有了外部传入的rootWidget
做为它的子视图。 RenderObjectToWidgetAdapter.createElement
建立的元素被赋值给了_renderViewElement
,_renderViewElement
被WidgetsBinding
实例持有。
那根渲染又是什么时候建立的呢?继续看mount
的调用序列:
RenderObjectToWidgetElement<RenderBox>.mount
RootRenderObjectElement.mount
RenderObjectElement.mount
RenderObjectWidget.createRenderObject => RenderObjectToWidgetAdapter.createRenderObject
复制代码
这里容易让人误导,调用createRenderObject
的实际上是RenderObjectElement
持有的RenderObjectWidget
, 而元素RenderObjectToWidgetElement
正是RenderObjectToWidgetElement<T> createElement() => RenderObjectToWidgetElement<T>(this)
(widgets/binding.dart:833)所建立,这里的this
其实就是RenderObjectToWidgetAdapter
,因此根渲染是RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container;
(widgets/bindings.836),可见根渲染不是在此时建立的,而是预先被赋值仅在此时返回的。
因而可知MyApp
做为外部传入的rootWidget
不是真正的根视图,真正的根视图实际上是RenderObjectToWidgetAdapter
, 它被RenderObjectToWidgetElement<RenderBox>
持有(一个Element持有一个Widget), 而这个Element被全局WidgetsBinding
实例持有,因此根元素为RenderObjectToWidgetElement<RenderBox>
。
RenderObjectElement
在mount
的时机建立了一个RenderObject
实例并持有,而RenderObjectToWidgetElement
是RenderObjectElement
的子类,建立的RenderObject
具体类型为RenderObjectWithChildMixin<RenderBox>
,因此它才是最终的根渲染。
有了rootElement
就能够找到rootWidget
和rootRenderObject
, 元素树,视图树与渲染树由此创建起来。
回到RenderObjectToWidgetAdapter
调用构造函数的地方,传入的container
是RenderingBinding
的RenderView get renderView => _pipelineOwner.rootNode;
(rendering/binding.dart:162, attachRootWidget
是WidgetsBinding
的方法,但 mixin WidgetsBinding on RendererBinding
,因此能够引用到RenderingBinding
的成员)。
那么rootRenderObject,也就是上面的RenderView
, 做为RenderObjectWithChildMixin<RenderBox>
的子类(class RenderView with RenderObjectWithChildMixin<RenderBox>
),又是在什么时机建立的?跟踪下来正是在初始化调用中:
runApp
WidgetsFlutterBinding.ensureInitialized
WidgetsFlutterBinding()
BindingBase()
WidgetsBinding.initInstances
RendererBinding.initInstances
_pipelineOwner = PipelineOwner(
RendererBinding.initRenderView
renderView = RenderView()
_pipelineOwner.rootNode = value;
复制代码
也就是说WidgetBinding把RendererBinding(mixin WidgetBinding with RendererBinding
)的renderView
做为了根渲染,而它实际是_pipelineOwner.rootNode
。
至此,咱们便知道了全部节点遍历的起点。