生命周期

flutter的渲染就是在维护三颗树:Widget树、Element树、RenderObject树,其中Widget树负责配置,Element树负责管理生命周期和维护这三棵树,RenderObject树负责布局和渲染。

渲染的入口是WidgetsFlutterBinding#scheduleAttachRootWidget方法,这里面构造了根节点。

Element的生命周期

  • Element是由根Element调用inflateWidget方法创建并配置的
    • 利用Widget#createElement创建出来Element
    • 利用Element#mount方法对创建出来的Element进行配置
  • Element#mount - 当Element首次被添加时调用,将Element添加到Element树中
    • ComponentElement重写了该方法,还会负责创建子widget对应的Element树,也就是会先通过build拿到一颗子Widget树,然后调用Element#inflateWidget方法对其进行配置,递归的配置Element;
    • RenderObjectElement重写了该方法,还会利用widget#createRenderObject创建RenderObject对象并利用attachRenderObject方法将其添加到RenderObject树中;
      • 更进一步的,MultiChildRenderObjectElement重写了该方法,还会负责为所有children widget利用inflateWidget创建出来对应的Element,递归的配置Element;
      • SliverMultiBoxAdaptorElement是Sliver list widget对应的Element,和上面的MultiChild版本不同的是这个Element虽然也负责管理子Element和布局,但它会按需创建Element,在mount阶段由于还不能确定布局,因此还无法创建子Element,它的子Element是由RenderObject在布局期间创建的;
  • Element#update- 当Element的widget有改变需要更新时调用,Element实现中只是简单的更新widget引用
    • RenderObjectElement还会利用Widget#updateRenderObject更新RenderObject,这样后面布局和渲染时就会利用更新后的属性来进行了;
      • 一些负责布局的Element,都是MultiChildRenderObjectElement的子类,在这个父类中update方法被重写了,每当widget更新时,都会利用updateChildren方法,对widget的所有子widget基于key做精细的比较,尽可能复用;
      • SliverMultiBoxAdaptorElement也会在update时检查所有已经按需创建过的widget和element,如果delegate在builder中返回了带有key的widget,而且提供了findIndexByKey方法,flutter就会利用findIndexByKey来在item顺序变化时同步的更新内部维护的Element的顺序,这样如果item本身没有变化而仅仅是顺序改变了,就可以继续重用原来和那个item对应的Element,避免更新;
    • StatelessElement和StatefulElement都会在update时利用build方法建立新的子Widget树,并和老的Widget树对比,看能否更新(类型和key都一样):若可以更新就递归的调用子Element的update方法来更新它;如果无法更新就把老的Element给干掉(会等到当前这次遍历结束后再调用unmount回调);
      • 由于StatefulElement的状态是由State决定的,而不完全是由Widget决定的,因此我们必须确保widget和state能够对应上,flutter的声明式UI框架允许我们声明widget的key,这个key在同一个父布局下使用多个StatefulWidget,并且它们的顺序可能变化时是必需提供的,不然flutter就会搞错widget和state的关系;