Flutter 表示层的内部结构

本文最后更新于 2021年4月4日 晚上

看了一篇讲 Flutter 的文章, 然后将这篇的内容浓缩了一下.

结构

Flutter Community.

参考这个链接, 也是 Flutter 社区中的一篇文章.

比如有如下代码:

1
2
3
4
5
6
7
8
9
10
void main() => runApp(SimpleApp());

class SimpleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Text('Hello World'),
);
}
}

下面就来对流程进行分析.

三棵树

runApp首次执行时, 会发生如下动作:

  1. Flutter 创建一颗包含上面代码中三个 Widget 的树, 即 App–>Container–>Text.
  2. Flutter 遍历 Widget 树, 针对每个 Widget 调用其 createElement 方法, 从而生成一颗对应的 Element 树.
  3. 同时, Flutter 调用每个 ElementcreateRenderObject 方法, 从而生成第三棵 RenderObject 树.

在这里面, 每个 Element 会持有其对应的 WidgetRenderObject 的引用.

RenderObject

它内部包含渲染 Widget 的所有逻辑, 包括布局, 绘制, 以及点击处理.

且它的初始化过程十分”昂贵”, 故策略就是尽量去重用已创建的 RenderObject.

而 Element 正是这样重用的媒介, 它作为不可变的 Widget 和可变的 RenderObject 间的桥梁, 在它内部包含了高效的比较算法, 通过比较 Widget 和 RenderObject 间的差异, 从而确定 RenderObject 的改变.

这样的话就可以尽量重用 RenderObject, 而且可以把改变只限制在某些节点或子树中, 从而达到很高的性能.

Widget 由于十分轻量, 故它们非常适合用于描述当前 APP 的状态(有时也称为App 的 configuration).

而在日常开发中, 很少直接接触 Element 对象的原因是: Flutter 将 Element 对象包装在 BuildContext 接口对象内, 在 build(BuildContext context) 方法中获取封装了不同 Element 对象的 BuildContext.

这也是为什么不同的 Widget 会对应不同的 BuildContext 的原因.

下一帧

由于 Widget 对象是不可变的, 当 configuration 发生改变(即 Widget 或其属性发生改变), Flutter 将会重建 Widget 树. 树重建时, 根据 Element 树从上往下依次对每个节点进行改变检测(对比 Widget 和对应的 RenderObject), 流程如下:

  • 从根节点开始,

  • 若对应位置节点 Widget 类型发生改变, 则将三棵树中对应位置的对象均移除掉, 然后替换为新的(Widget, Element, RenderObject).

  • 若 Widget 类型没有改变, 则只是更新 RenderObject 的配置(避免新建), 然后请求它进行重绘, 从而更新显示.

  • 没有改变的节点不会进行任何操作.

  • 往后遍历继续执行上述两条规则,

具体的还需要看源码以完全确定.


Flutter 表示层的内部结构
https://blog.rayy.top/2019/01/06/2019-30-flutter-inner/
作者
貘鸣
发布于
2019年1月6日
许可协议