1. Flutter有状态Widget在底层渲染树中的表现
- 创建阶段:
- 当一个有状态Widget被插入到Widget树时,Flutter框架会调用其
createState
方法创建一个对应的State
对象。例如,对于自定义的MyStatefulWidget
,会创建MyStatefulWidgetState
。
- 这个
State
对象会被关联到Element
树上。在Flutter中,Element
是Widget在树中的实例化表示。有状态Widget对应的Element
是StatefulElement
。
- 源码中,
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
对象的引用,形成一种紧密的联系。StatefulElement
在mount
过程中,会调用state.initState
,这是State
对象的生命周期方法,通常用于初始化一些状态数据等操作。
- 更新阶段:
- 当有状态Widget的配置(如通过
InheritedWidget
传递的数据发生变化,或者父Widget传递的参数改变)发生改变时,Flutter框架会调用StatefulElement
的update
方法。
- 在
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)阶段。
- 在布局阶段,
RenderObjectElement
(StatefulElement
的父类也是RenderObjectElement
)会将布局约束传递给对应的RenderObject
。RenderObject
会根据这些约束计算自身的大小和位置。例如,RenderBox
是用于布局和绘制矩形区域的RenderObject
子类,它会根据父级的约束和自身的属性(如width
、height
等)来确定自己的大小和位置。
- 绘制阶段,
RenderObject
会将自身绘制到画布(Canvas
)上。不同类型的RenderObject
有不同的绘制逻辑,如RenderImage
用于绘制图片,RenderParagraph
用于绘制文本段落等。
- 引擎层处理与屏幕显示:
- Flutter引擎会将绘制好的图层(
Layer
)组合成一个场景(Scene
)。这些图层包含了各种图形元素,如文本、图像、形状等。
- 引擎会将这个场景发送到平台视图(在不同平台上,如Android的
SurfaceView
或iOS的CAEAGLLayer
)进行渲染。在Android上,Flutter使用Skia图形库进行渲染,Skia会将场景中的图形数据转换为像素数据,并最终显示在屏幕上。在iOS上,Flutter使用Metal(默认)或OpenGL进行渲染,将场景渲染到屏幕上。