Flutter - 从 runApp 方法开始,聊一聊 Render

顺着代码看:

入口函数 main

Dart 是从 main 方法开始的,通过 runApp 方法把做为 App 的 Widget 构建出来:

image.png

runApp 方法

image.png 可以注意到,runApp 方法会初始化一个 WidgetsFlutterBinding 对象,然后通过 scheduleAttachRootWidget 方法,把 App 小组件安排到了根小组件上。

attachRootWidget 方法

image.png 可以发现我们的 App 被当作成 rootWidget,在 attachRootWidget 方法中,通过 RenderObjectToWidgetAdapter 这个 Widget,把 App 作为 child 来构建它,然后执行了它的 attachToRenderTree 方法。由于 renderViewElement 是跟随 WidgetsFlutterBinding 一同被构建的,而 renderViewElement 还没有被实例化,所以传进方法内的值为 null。

attachToRenderTree 方法

image.png elementnull,则会依次执行 createElementmount 方法。

createElement 方法

image.png createElement 会实例化一个叫做 RenderObjectToWidgetElementElement,并把自己(RenderObjectToWidgetAdapter)作为 property 传入。

mount 方法

image.png mount 可以理解为安装,可以看到第 5662 行,刚才作为 property 传入的 widgetRenderObjectToWidgetAdapter)执行了 createRenderObject 方法,并且把自己(RenderObjectToWidgetElement)作为 property 传进方法里。

看到这里,WidgetElementRenderObject 这三个大名鼎鼎的关键词都已经出现了,但他们的关系好乱,我们继续看:

createRenderObject 方法

image.png

image.png 通过 RenderObjectToWidgetAdaptercreateRenderObject 方法后,我们得到了 RenderObject。这个 RenderObject 是什么?通过 1099 行,再到 1090 行,再到 1080 行,我们返回到初始化 RenderObjectToWidgetAdapter 的地方,看看第二个参数是什么:

image.png 所以绕了一大圈,我们知道了,通过 createRenderObject 方法拿到的是随着 WidgetsFlutterBinding 一同产生的一个叫 renderViewRenderObject

_rebuild 方法

刚才的 mount 方法我们才看了一半,接下来的第 1171 行,执行了 _rebuild 方法: image.png

image.png 这个方法里执行了一个叫做 updateChild 的方法,这个方法的第二个参数 (widget as RenderObjectToWidgetAdapter<T>).child,就是我们最开始传入的 App。

updateChild 方法

我们来看看 updateChild 方法是怎么说的:

image.png 这个可是尤其重要的一个方法。

inflateWidget 方法

接下来会进到 inflateWidget 方法:

image.png

image.png inflateWidget 方法里会用我的 App 来执行 createElement 方法,因为我的 App 是继承的 StatelessWidget,所以 createElement 方法会建立一个 StatelessElement 并把自己(StatelessWidget)当成 property 传进 StatelessElement 内来使之构造。所以在这里 newChildStatelessElement,接着第 3817 行会将 StatelessElement 执行 mount 方法,把 thisRenderView)传进方法里。上面说到了,mount 可以理解为安装,所以这行方法等于是让 StatelessElement 拿着 RenderObjectRenderView)。

执行 mount 方法,又回到了这里:

image.png

attachRenderObject 方法

接着执行 attachRenderObject方法:

image.png 该方法内,_findAncestorRenderObjectElement 顾名思义,查找祖先的 RenderObjectElement,最上面最上面我们还记得,祖先 RenderObjectElementRenderObjectToWidgetElement

再进入 RenderObjectToWidgetElementinsertRenderObjectChild 方法:

image.png 我们来看第 1223 行。

renderObject 是谁呢?renderObjectWidgetsFlutterBindingrenderView

child 是谁呢?是我们 App 的 RenderObject,也就是 StatelessElement 拿着的那个 RenderObject

到这里,终于把 App 的 RenderObjectWidgetsFlutterBindingRenderObject 绑在了一起。

小结一下:

  1. 塞了一个 WidgetrunApp
  2. 实例化了一个附带 RenderObjectrenderView)的 WidgetsFlutterBinding
  3. 实例化了一个 RenderObjectToWidgetAdapter
  4. 利用 RenderObjectToWidgetAdapter 实例化了一个 RenderObjectToWidgetElement 并将RenderObjectToWidgetAdapter 作为 RenderObjectToWidgetElementproperty
  5. RenderObjectToWidgetElement 会通过 createElement 产生传入 runAppWidgetElement
  6. 利用 Widget 产生的 Element 通过 Widget 产生 RenderObject
  7. 利用 RenderObjectToWidgetElementWidgetRenderObject 变成 WidgetsFlutterBindingrenderViewchild,并将其作为 root widget

所以我们了解到, RenderObject 是通过 Element 利用 Widget 产生出来的,而 Element 是由 Widget 产生出来的。 image.png

做完以上,接着通过 scheduleWarmUpFrame 就会把 widget 提供的配置信息 render 在手机屏幕上了。

RenderObject 到底是个啥

待续

Widget、Element、RenderObject 三者的关系

待续

猜你喜欢

转载自juejin.im/post/7110152555723751438