Flutter的Widget-Element-RenderObject flutter的渲染过程01

Flutter的Widget-Element-RenderObject

我的图片有些时候看得到水印 因为这个是我们的老师上课用的东西

  • 如果觉得有些东西不清楚可以去看老师的微信公众号 coderwhy
  • 这里只是把他上课的东西整理成笔记了

这个东西是flutter的渲染过程

这个东西虽然对我们代码没有直接关系 但是它可以让你写代码更加自信

这节课可以解决的问题

  • BuildContext 是什么东西
  • Widget频繁的创建 会不会影响性能
  • State和StatefulWidget 的关系
  • Key的用法

一. Flutter的渲染过程

1. 1 Widget-Element-RenderObject的关系

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第1张图片
树结构 - 数据结构 它是一种非常重要的数据结构

我们使用flutter开发东西的时候 我们开发出来的东西的时候都是用Widget来进行搭建的

所以我们写的代码其实就是一个一个的Widget

他们之间存在一定的层级关系

比如MyApp就是我们的顶层 然后里面是HYHomePage 然后是其他的东西
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第2张图片
这种结构就是一个树结构

所以这种Widget结构就是一个Widget树

我们运行flutter代码是基于Flutter SDK 这个里面有一个特别重要的东西

flutter Engine 它需要把我们的最终的界面 渲染成最终的界面

比如我们最后写了 一个Text那我们的flutter引擎是不是 就会解析这个Wiget然后把它显示到界面上

  • 但是其实并不是
    Flutter的Widget-Element-RenderObject flutter的渲染过程01_第3张图片
    flutter Engine它并不直接渲染Widget tree

因为我们在flutter 中Widget tree 是特别不稳定的

因为它动不动就会重新调用build方法 一旦调用build方法

build -> Widget -> Widget -> Widget 而且中间会依赖很多的Widget 一旦build 下面所有的Widget 都会重新创建

意味着整个Widget树都是不稳定的

而且一build里面的布局啊那些东西都是会变化的 我们的flutter 性能是做不到很高的

所以这个东西并不是直接渲染Widget的

我们这里还有一个对应的树结构

  • 叫做RenderObjectTree
    Flutter的Widget-Element-RenderObject flutter的渲染过程01_第4张图片

我们真正渲染的Widget就是它们

但是你看这里Widget tree 和Render tree 并不是一一对应的关系的

这个是因为很多的Widget 它其实更多的是一个盒子的作用并不是一个可渲染的东西

甚至我们的Text 它是继承至StatelessWidget那我们就会看他的build方法

哪个RichText才是最终渲染的在这里插入图片描述

然后我们再点RichText
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第5张图片
这里它就继承至 xxRenderObjectWidget

继承制这种Widget才是flutter最终渲染的出来的Widget

Widget tree =》 Render tree 这样才能最终渲染出来

但是你进到Text , opacity, 甚至RichText里面它都是一些属性 它还是没有渲染的东西

在这里插入图片描述

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第6张图片

渲染的时候我们需要做一个事 是要做layout 然后再做一个paint

layout -> paint

只要的你的东西是一个Widget它就没有任何layout相关的东西 也 没有任何和paint相关的东西

所以他们之间存在这样的关系

他们的这种关系其实借鉴react里面的虚拟dom

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第7张图片
在早期的web的时候 你通过js生成的html代码 他是直接转换成真实的dom

但是这样它是非常消耗性能的, 它的代价是非常消耗性能的

如果我们的js里面改了一点点html的代码 我们就要操作dom这个是非常消耗性能的

  • 所以React里面就提出了一个概念 虚拟dom的概念
  • 意思是 加了一层东西
  • 如果js中改了html代码 它就去改虚拟dom

这个虚拟dom就像一个中间商
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第8张图片
如果你改了html代码 它就会生成一个新的虚拟dom和原来的来做一个对比

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第9张图片
这里就会用到diff算法 (different) 然后它就会把原来的地方打一个patch(补丁)
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第10张图片
现在这里flutter这里的三棵树就基本和react 虚拟dom是一样的
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第11张图片
到时候 你如果进行了修改之类的 他就会对比之前的东西 类型是否一样 key值是否一样

如果都一样 那么我们完全没有必要更新我们的Element 也就是我们的我们RenderObject完全没有必要重新创建这个东西 (可能widget里面是重新创建了一个对象 但是Element只是更新一个属性就可以了) 同理和RenderObject
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第12张图片

1.2 Widget 是什么

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第13张图片
官方对Widget的说明:

  • Flutter的Widgets的灵感来自React,中心思想是构造你的UI使用这些Widgets。
  • Widget使用配置和状态,描述这个View(界面)应该长什么样子。
  • 当一个Widget发生改变时,Widget就会重新build它的描述,框架会和之前的描述进行对比,来决定使用最小的改变(minimal changes)在渲染树中,从一个状态到另一个状态。

老师的理解:

  • Widget就是一个个描述文件,这些描述文件在我们进行状态改变时会不断的build。
  • 但是对于渲染对象来说,只会使用最小的开销来更新渲染界面。

1.3 Element是什么

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第14张图片
官方对Element的描述:

  • Element是一个Widget的实例,在树中详细的位置。
  • Widget描述和配置子树的样子,而Element实际去配置在Element树中特定的位置。

1.4 RenderObject 是什么

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第15张图片
官方对RenderObject的描述:

  • 渲染树上的一个对象
  • RenderObject层是渲染库的核心。

二. 对象的创建过程(这个创建的过程是否真会创建Element Render Widget树)

我们常见的几种构建的Widget在渲染的层面主要分成两种

  1. 组件Widget: 不会生成RenderObject
  • Containr
  • Text
  • HYHomePage
  1. 渲染Widget: 会生成RenderObject
  • Padding
  • Row

我们现在点到Padding 里面
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第16张图片
然后我们发现这个Padding它是继承至 SingleChildRenderObjectWidget

这个是一个XXRenderObject的形式

然后这个SingleChildRenderObjectWidget它又继承至谁呢
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第17张图片

Padding -> SingleChildRenderObjectWidget -> RenderObjectWidget

而Container

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第18张图片

在这里插入图片描述

Container -> StatelessWidget -> Widget

所以Widget有那些子类呢 StatelessWidget StatefulWidget然后就是RenderObjectWidget
在这里插入图片描述
这个RenderObjectWidget 它有一个方法 createRenderObject
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第19张图片
也就是说到这里的时候它有一个核心的方法 createRenderObject

这里它是一个抽象方法 可见这个方法他是没有实现的 那就是在子类中实现的(其实并没有在这个子类中实现)
Padding -> SingleChildRenderObjectWidget -> RenderObjectWidget
但是这个子类也没有实现
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第20张图片
但是也没关系因为这个也是一个抽象类 所以我们到它的子类Padding里面去
在这里插入图片描述
Padding里面就有实现了
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第21张图片
然后传入一些东西返回了一个东西 这个东西叫RenderPadding
在这里插入图片描述
然后它有继承关系 就点到父类去
在这里插入图片描述
再点进RenderBox里面

然后你就发现它继承至 RenderObject
在这里插入图片描述





  • 继承关系:
    在这里插入图片描述
  • 方法关系:

Padding -> createRenderObject -> RenderPadding -> … -> RenderBox -> RenderObject

  • 所以Padding这个类是在继承至RenderObjectWidget的方法createRenderObject
  • createRenderObject方法中创建了一个 RenderOject对象

所以很可能这个地方它就创建了一个Render树上的对象





但是我们现在并没有看到这个东西的调用的地方

但是如果你去其他的Container 里面 它是没有这个creatRenderObject 这个方法来创建一个RenderObject对象的

那我们现在就要知道它在什么地方调用创建的这个RenderObject的

我们点到Padding里面发现这个里面 是没有这个createRenderObject相关的东西的
Padding -> SingleChildRenderObjectWidget -> RenderObjectWidget
那我们就到它的父类SingleChildRenderObjectWidget

然后在父类里面有一个方法叫做 createElement 那这个方法是噶你什么的呢
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第22张图片
我们来到 Widget
Padding -> SingleChildRenderObjectWidget -> RenderObject -> Widget
在这里插入图片描述
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第23张图片
这个Widget它有一个抽象方法 createElement 这个东西是所有的Widget的父类

所以它所有的子类都是有这个方法的 它最终都是会实现这个方法的

createElement 方法 要么在某一个类里面实现 要么在子类中实现 要么在中间的某个类实现
在这里插入图片描述
每个类都会实现这个方法 只是说每个类实现的方式是不一样的

Padding虽然没有实现这个方法但是在它的父类SingleChildRenderObjectWidget是实现了这个方法的

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第24张图片
那我们来看看Container里面的这个方法

Container里面是没有实现这个方法的
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第25张图片
所以我们去它的父类去找

可见这个
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第26张图片

所以我们可以下结论了 所有的Widget都会创建Element对象

不论它是渲染Widget还是组件Widget

但是这边创建的Element对象是不一样的

我们看到这个StatelessWidget 的方法 创建的Element对象叫做 StatelessElement
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第27张图片
如过现在到StatefulWidget里面去看
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第28张图片
它创建的是这个Element

但是它们是有相似的地方的

你会发现他们都是继承至ComponentElement
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第29张图片

  • 它们的本质是一样的 它们都是继承至ComponentElement这个Element的

但是StatefulWidget会比StatelessWidget多一些属性

  • StatelessWidget
  • StatefulWidget -> State

同样的Padding 父类SingleChildRenderObjectWidget 也有这个方法 同样也会创建Element对象
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第30张图片
但是 渲染Widget 和 组件Widget 他们是不一样的

  1. 写Widget
  2. 某些Widget会创建RenderObject
  3. 所有的Widget都会创建Element对象
  4. mount 方法

这个方法是flutter Engine会调用的方法

我们点到ElementWidget里面去
在这里插入图片描述
然后点到它的根Widget Element里面去
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第31张图片
这个地方有一个mount方法

所有的widget都有element 同时element的根有mount这个方法

Flutter的Widget-Element-RenderObject flutter的渲染过程01_第32张图片

  1. 写Widget
  2. 某些Widget会创建RenderObject
  3. 所有的Widget都会创建Element对象
  4. mount 方法:

我们来到这个StatelessElement
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第33张图片
但是它没有这个mount方法

所以它的父类必然是有这个方法的
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第34张图片
然后你注意到它执行了一个_fristBuild方法
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第35张图片
我们点进去
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第36张图片
然后这里执行了一个performRebuild方法
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第37张图片
然后就发现这个东西没有实现
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第38张图片

那我们就要看它的实现 我们需要去看它的Components的实现 因为我们是从Components点过来的嘛
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第39张图片
这里就需要看大量的源码

然后它这里干了一件事 它调用了一下这个build方法

这个build() 结果就是 Widget

也就是说我们的这个Element 里面build
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第40张图片

然后再点进去

这个东西是一个抽象的方法

在这里插入图片描述

所以我们再找它的实现方法
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第41张图片
同样我们找 StateElement里的这个方法
在这里插入图片描述
然后发现这个东西它掉了一个下Widget的build方法

  • 所以你看创建Element系统在调mount方法的时候
  • 它调用了_fristBuild -> rebuild -> performBuild -> build -> widget.build

我猜这里就是将Widget和Element链接起来了

那这个widget 是谁呢

我们来到这个StatelessWidget里面的createElement
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第42张图片
我们发现这个地方我们创建StatelessWidget的时候把this传进去了

这个this 是谁 这个this在Widget里面那这个this就是一个widget

我们点进去

发现这个东西传给父类了
在这里插入图片描述
同理
在这里插入图片描述
然后我们就看到在根的Element里面这个东西_widget被赋值为传入的widget
Flutter的Widget-Element-RenderObject flutter的渲染过程01_第43张图片

所以传入的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里面

你可能感兴趣的:(flutter,flutter)