MST

星途 面试题库

面试题:Flutter有状态Widget与底层渲染机制的交互

深入剖析Flutter有状态Widget在底层渲染树中的表现,以及其状态变化如何通过引擎层最终反映在屏幕上。请结合Flutter的渲染架构和相关源码进行说明。
48.0万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

1. Flutter有状态Widget在底层渲染树中的表现

  • 创建阶段
    • 当一个有状态Widget被插入到Widget树时,Flutter框架会调用其createState方法创建一个对应的State对象。例如,对于自定义的MyStatefulWidget,会创建MyStatefulWidgetState
    • 这个State对象会被关联到Element树上。在Flutter中,Element是Widget在树中的实例化表示。有状态Widget对应的ElementStatefulElement
    • 源码中,StatefulWidget类定义如下:
abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key? key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);
  abstract State createState();
}
  • 这里createElement方法返回StatefulElement,而createState方法由子类实现,用于创建具体的State对象。
  • StatefulElement会持有State对象的引用,形成一种紧密的联系。StatefulElementmount过程中,会调用state.initState,这是State对象的生命周期方法,通常用于初始化一些状态数据等操作。
  • 更新阶段
    • 当有状态Widget的配置(如通过InheritedWidget传递的数据发生变化,或者父Widget传递的参数改变)发生改变时,Flutter框架会调用StatefulElementupdate方法。
    • update方法中,会对比新旧Widget的配置,若有差异,会调用state.didUpdateWidget方法通知State对象,Widget的配置发生了变化。State对象可以根据这个变化做出相应的调整,比如重新加载数据等。

2. 状态变化通过引擎层最终反映在屏幕上的过程

  • 状态变化通知
    • State对象的状态发生变化时,例如调用了setState方法。setState方法会标记State对象为脏状态(dirty)。
    • setState源码如下:
void setState(VoidCallback fn) {
  assert(fn != null);
  assert(() {
    if (_debugLifecycleState == _StateLifecycle.defunct) {
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('setState() called after dispose(): $this'),
        ErrorDescription(
          'This error happens if you call setState() on a State object for a widget that no longer appears '
          'in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This '
          'error can occur when code calls setState() from a timer or an animation callback.'
        ),
        ErrorHint(
          'The preferred solution is to cancel the timer or stop listening to the animation in the dispose() '
          'callback. Another solution is to check the "mounted" property of this object before calling setState() '
          'to ensure the object is still in the tree.'
        ),
        ErrorHint(
          'This error might indicate a memory leak if setState() is being called because another object is '
          'retaining a reference to this State object after it has been removed from the tree. To avoid '
          'memory leaks, consider breaking the reference to this object during dispose().'
        ),
      ]);
    }
    return true;
  }());
  _element!.markNeedsBuild();
}
  • 这里_element!.markNeedsBuild()会标记对应的StatefulElement需要重新构建。
  • 重新构建与布局
    • StatefulElement被标记为需要重新构建时,会调用build方法重新构建Widget。这个过程会重新生成Widget树的一部分(从这个StatefulElement开始向下的子树)。
    • 重新构建后的Widget树会被用于更新Element树。接着,Flutter会进行布局(layout)和绘制(paint)阶段。
    • 在布局阶段,RenderObjectElementStatefulElement的父类也是RenderObjectElement)会将布局约束传递给对应的RenderObjectRenderObject会根据这些约束计算自身的大小和位置。例如,RenderBox是用于布局和绘制矩形区域的RenderObject子类,它会根据父级的约束和自身的属性(如widthheight等)来确定自己的大小和位置。
    • 绘制阶段,RenderObject会将自身绘制到画布(Canvas)上。不同类型的RenderObject有不同的绘制逻辑,如RenderImage用于绘制图片,RenderParagraph用于绘制文本段落等。
  • 引擎层处理与屏幕显示
    • Flutter引擎会将绘制好的图层(Layer)组合成一个场景(Scene)。这些图层包含了各种图形元素,如文本、图像、形状等。
    • 引擎会将这个场景发送到平台视图(在不同平台上,如Android的SurfaceView或iOS的CAEAGLLayer)进行渲染。在Android上,Flutter使用Skia图形库进行渲染,Skia会将场景中的图形数据转换为像素数据,并最终显示在屏幕上。在iOS上,Flutter使用Metal(默认)或OpenGL进行渲染,将场景渲染到屏幕上。