这个东西是flutter的渲染过程
这个东西虽然对我们代码没有直接关系 但是它可以让你写代码更加自信
这节课可以解决的问题
我们使用flutter开发东西的时候 我们开发出来的东西的时候都是用Widget来进行搭建的
所以我们写的代码其实就是一个一个的Widget
他们之间存在一定的层级关系
比如MyApp就是我们的顶层 然后里面是HYHomePage 然后是其他的东西
这种结构就是一个树结构
所以这种Widget结构就是一个Widget树
我们运行flutter代码是基于Flutter SDK 这个里面有一个特别重要的东西
flutter Engine 它需要把我们的最终的界面 渲染成最终的界面
比如我们最后写了 一个Text那我们的flutter引擎是不是 就会解析这个Wiget然后把它显示到界面上
因为我们在flutter 中Widget tree 是特别不稳定的
因为它动不动就会重新调用build方法 一旦调用build方法
build -> Widget -> Widget -> Widget 而且中间会依赖很多的Widget 一旦build 下面所有的Widget 都会重新创建
意味着整个Widget树都是不稳定的
而且一build里面的布局啊那些东西都是会变化的 我们的flutter 性能是做不到很高的
所以这个东西并不是直接渲染Widget的
我们这里还有一个对应的树结构
我们真正渲染的Widget就是它们
但是你看这里Widget tree 和Render tree 并不是一一对应的关系的
这个是因为很多的Widget 它其实更多的是一个盒子的作用并不是一个可渲染的东西
甚至我们的Text 它是继承至StatelessWidget那我们就会看他的build方法
哪个RichText才是最终渲染的
然后我们再点RichText
这里它就继承至 xxRenderObjectWidget
继承制这种Widget才是flutter最终渲染的出来的Widget
Widget tree =》 Render tree 这样才能最终渲染出来
但是你进到Text , opacity, 甚至RichText里面它都是一些属性 它还是没有渲染的东西
渲染的时候我们需要做一个事 是要做layout 然后再做一个paint
layout -> paint
只要的你的东西是一个Widget它就没有任何layout相关的东西 也 没有任何和paint相关的东西
所以他们之间存在这样的关系
他们的这种关系其实借鉴react里面的虚拟dom
在早期的web的时候 你通过js生成的html代码 他是直接转换成真实的dom
但是这样它是非常消耗性能的, 它的代价是非常消耗性能的
如果我们的js里面改了一点点html的代码 我们就要操作dom这个是非常消耗性能的
这个虚拟dom就像一个中间商
如果你改了html代码 它就会生成一个新的虚拟dom和原来的来做一个对比
这里就会用到diff算法 (different) 然后它就会把原来的地方打一个patch(补丁)
现在这里flutter这里的三棵树就基本和react 虚拟dom是一样的
到时候 你如果进行了修改之类的 他就会对比之前的东西 类型是否一样 key值是否一样
如果都一样 那么我们完全没有必要更新我们的Element 也就是我们的我们RenderObject完全没有必要重新创建这个东西 (可能widget里面是重新创建了一个对象 但是Element只是更新一个属性就可以了) 同理和RenderObject
老师的理解:
我们常见的几种构建的Widget在渲染的层面主要分成两种
我们现在点到Padding 里面
然后我们发现这个Padding它是继承至 SingleChildRenderObjectWidget
这个是一个XXRenderObject的形式
然后这个SingleChildRenderObjectWidget它又继承至谁呢
Padding -> SingleChildRenderObjectWidget -> RenderObjectWidget
而Container
Container -> StatelessWidget -> Widget
所以Widget有那些子类呢 StatelessWidget StatefulWidget然后就是RenderObjectWidget
这个RenderObjectWidget 它有一个方法 createRenderObject
也就是说到这里的时候它有一个核心的方法 createRenderObject
这里它是一个抽象方法 可见这个方法他是没有实现的 那就是在子类中实现的(其实并没有在这个子类中实现)
但是这个子类也没有实现
但是也没关系因为这个也是一个抽象类 所以我们到它的子类Padding里面去
Padding里面就有实现了
然后传入一些东西返回了一个东西 这个东西叫RenderPadding
然后它有继承关系 就点到父类去
再点进RenderBox里面
Padding -> createRenderObject -> RenderPadding -> … -> RenderBox -> RenderObject
所以很可能这个地方它就创建了一个Render树上的对象
但是我们现在并没有看到这个东西的调用的地方
但是如果你去其他的Container 里面 它是没有这个creatRenderObject 这个方法来创建一个RenderObject对象的
那我们现在就要知道它在什么地方调用创建的这个RenderObject的
我们点到Padding里面发现这个里面 是没有这个createRenderObject相关的东西的
那我们就到它的父类SingleChildRenderObjectWidget
然后在父类里面有一个方法叫做 createElement 那这个方法是噶你什么的呢
我们来到 Widget
这个Widget它有一个抽象方法 createElement 这个东西是所有的Widget的父类
所以它所有的子类都是有这个方法的 它最终都是会实现这个方法的
createElement 方法 要么在某一个类里面实现 要么在子类中实现 要么在中间的某个类实现
每个类都会实现这个方法 只是说每个类实现的方式是不一样的
Padding虽然没有实现这个方法但是在它的父类SingleChildRenderObjectWidget是实现了这个方法的
Container里面是没有实现这个方法的
所以我们去它的父类去找
所以我们可以下结论了 所有的Widget都会创建Element对象
不论它是渲染Widget还是组件Widget
但是这边创建的Element对象是不一样的
我们看到这个StatelessWidget 的方法 创建的Element对象叫做 StatelessElement
如过现在到StatefulWidget里面去看
它创建的是这个Element
但是它们是有相似的地方的
但是StatefulWidget会比StatelessWidget多一些属性
同样的Padding 父类SingleChildRenderObjectWidget 也有这个方法 同样也会创建Element对象
但是 渲染Widget 和 组件Widget 他们是不一样的
这个方法是flutter Engine会调用的方法
我们点到ElementWidget里面去
然后点到它的根Widget Element里面去
这个地方有一个mount方法
所有的widget都有element 同时element的根有mount这个方法
我们来到这个StatelessElement
但是它没有这个mount方法
所以它的父类必然是有这个方法的
然后你注意到它执行了一个_fristBuild方法
我们点进去
然后这里执行了一个performRebuild方法
然后就发现这个东西没有实现
那我们就要看它的实现 我们需要去看它的Components的实现 因为我们是从Components点过来的嘛
这里就需要看大量的源码
然后它这里干了一件事 它调用了一下这个build方法
这个build() 结果就是 Widget
然后再点进去
这个东西是一个抽象的方法
所以我们再找它的实现方法
同样我们找 StateElement里的这个方法
然后发现这个东西它掉了一个下Widget的build方法
我猜这里就是将Widget和Element链接起来了
那这个widget 是谁呢
我们来到这个StatelessWidget里面的createElement
我们发现这个地方我们创建StatelessWidget的时候把this传进去了
这个this 是谁 这个this在Widget里面那这个this就是一个widget
我们点进去
发现这个东西传给父类了
同理
然后我们就看到在根的Element里面这个东西_widget被赋值为传入的widget
所以传入的widget 是不是就是创建的widget啊
_fristBuild -> rebuild -> performBuild -> build -> widget.build
我们之前不是说 所有的widget创建以后都会调用自己的build方法
在哪调用的就是在这调用的
为什么每次我们的widget创建出来以后它会调用build方法呢
就是这样一步一步的调用的
我们在 所有的Widget的父类它有一个方法createElement
我们来到StatelessWidget的找到它的createElement 发现它是创建了一个StatelessElement然后再到它的父类ComponentElement
发现这个父类里面有一个mount 方法 这个mount比较关键
它里面调用了一个_fristBuild -> rebuild 这个方法也调用了Component方法里面的rebuild方法 我们再点到rebuild方法
发现这个方法来自于Element rebuild方法里面调用了performRebuild 方法 这个方法同样来自Element 但是它是一个抽象方法 所以我们去找它的子类
我们又来到ComponentElement它实现了这个方法 这个方法里面又一个重要的方法build 我们再点到build里面