likes
comments
collection
share

Flutter Element挂载核心逻辑分析

作者站长头像
站长
· 阅读数 59

前言

本篇主要介绍一下关于Flutter中父子Element如何实现挂载,Element树又是怎么样一个一个枝节节点完成搭建。尽管这些基础知识的文章介绍已经很多,但是相信5分钟看完本篇文章后你或许可以更透彻的理解这部分framework的源码逻辑。

本篇文章基于Flutter 3.7.1版本进行源码分析

开始分析

首先,贴一段看起来很...的代码:

Flutter Element挂载核心逻辑分析

我们要知道Flutter树结构是从上向下开始完成构建的,这里说的从上向下,通俗来讲就是先声明的Widget先构建,后声明的后构建。从这段代码片段里来看就是A→B→C,即元素深度是A先于B先于C的;

从这段及其简单及冗余的代码开始…我们先来理解一下这个步骤在framework代码中是怎么实现的;

可能有的朋友会说,这实际上就是一行代码,只是对象构造中的多层嵌套,最终return出去,明明是先执行了C而后是B再后才是A

没错,但是我们要知道,Flutter中每个Widget都可以理解为一个描述文件,传入的child以及其他各种配置参数只有在最终执行build方法的时候才会启动转换挂载;

Flutter Element挂载核心逻辑分析 这里就要追溯一下build方法在哪里被调用

Flutter Element挂载核心逻辑分析

这是Element类的mount方法,看起来好像并没有什么值得深入的东西,不过我们要知道Flutter是有多种Element的,这里我们就要看一下mount方法的子类实现

Flutter Element挂载核心逻辑分析

可以看到直接子类、间接子类种有非常多的方法重载;

回到上面的Container嵌套例子,我们就假设现在是ContainerA开始了挂载,来看一下其mount方法都做了什么逻辑,ContainerStatelessWidget,其对应的ElementStatelessElementStatelessElement 没有重写mount方法,其父类ComponentElement 进行了重写:

Flutter Element挂载核心逻辑分析

Flutter Element挂载核心逻辑分析

Flutter Element挂载核心逻辑分析

注意以上的mount_firstBuild方法块是ComponentElement中的,而rebuild方法又回到了Element中,继续看Element类中的performRebuild方法

Flutter Element挂载核心逻辑分析

Flutter 老版本此方法是抽象方法,强制子类实现;新版本(当前3.7.1)在父类中多了_dirty的赋值

不用怀疑,这就是一个要交给子类去重载的方法;

这里回到我们的例子中,我们现在假设上述看到的mount_firstBuildrebuild都是在ContainerA中的逻辑,而Container是一个StatelessWidget,其对应的ElementStatelessElement,而StatelessElement的父类是ComponentElement,我们来看看ComponentElement是如何重载这个父类”空“方法的:

Flutter Element挂载核心逻辑分析

这个方法里主要有两个重要的任务

  1. 调用自己的build方法,获取到一个Widget
  2. updateChild方法(这个方法是Element中的,也就是说这里从ComponentElement回到了父类中),返回值为_child变量赋值(_child是一个Element,是子类的Element

这里我们清楚一点,从我们的例子来解读,此处执行performRebuild的是ContainerAElement,所以这个build就是StatelessElementbuild方法:

Flutter Element挂载核心逻辑分析

这里就是我们熟知的Container类的build方法实现,这里就是对于传入的子Widget(即child)进行包装,然后返回一个Widget,看到这里,也就是我们的ContainerB,实际上就是被包装后赋值给了built变量,然后传入updateChild,这里先不深入,简单解释一下updateChild方法;

关于updateChild简单说明方法

Element类中的方法,主要负责的是更新子类,从方法入参可以看到,传入了_child,又将返回值给了_child,就是说这里面会进行一系列判断:子Element是否加载过?是否仅需更新而非重新构建?等等。无论如何,最终方法内会返回一个Element,并赋值给_child

尽管先不关注updateChild方法中的各种判断,不过有一个重要的点我们需要知道:

如果子Element(也就是我们例子中ContainerB对应的Element)之前不存在,需要重新构建一个,那么会进入其中的inflateWidget方法

Flutter Element挂载核心逻辑分析

这里面有两个我们熟悉的方法,createElementmount

Flutter Element挂载核心逻辑分析

至此,就完成了从ContainerAmountContainerBmount,就是我们的Element树的向下逐个挂载逻辑。


总结

看到这里我们只是看完了ComponentElement挂载的完整逻辑,至于其他类型的Element(比如RenderObjectElement),他们去加载子类Element的流程是不完全一样的,不过核心方法没有区别,最终都会进入它们的顶级父类Element中的updateChildinflateWidget等方法。

本篇先只梳理了ComponentElement的源码逻辑,最后做一下总结:

  • Element类中的mount方法里,只进行了一些通用的赋值操作,加载子类等操作都是在对应子Element的方法重载中
  • 最终加载子Element的核心方法是在顶级父类Element中的updateChildinflateWidget方法中
转载自:https://juejin.cn/post/7264111170411511866
评论
请登录