setState流程分析
一个匿名函数setState
的执行,背后竟然涉及State → Element → BuildOwner → PipelineOwner → Renderer
一套流程。
看看咋回事~
流程简析
StatefulWidget
有对应的State对象
。
State
和UI树
上的Element
绑定。
setState
的作用:修改State
内部数据,通知Flutter脏数据,触发一次Widget子树
的重新build
。
setState
dart
void setState(VoidCallback fn) {
assert(() {
if (_debugLifecycleState == _StateLifecycle.defunct) {
// ...
// 不希望在stf的defunct阶段调用
}
if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
// ...
// ui还没在树上,不需要更新
}
return true;
}());
// 执行传进来的方法,更新数据
final Object? result = fn() as dynamic;
assert(() {
// ...
// 不希望fn的返回值是future
return true;
}());
// 标记为脏
// _element 就是当前 State 绑定的 StatefulElement
_element!.markNeedsBuild();
}
StatefulElement.markNeedsBuild
dart
void markNeedsBuild() {
// ...
if (!_active)
return;
// ...
if (dirty)
return;
_dirty = true;
owner.scheduleBuildFor(this);
}
markNeedsBuild
会调用owner
的scheduleBuildFor
方法,将该element
标记为dirty
,并且将element
加入到一个全局的表示需要更新的Element列表
中。
owner
是BuildOwner
对象。
BuildOwner.scheduleBuildFor
dart
void scheduleBuildFor(Element element) {
// ...
final BuildScope buildScope = element.buildScope;
// ...
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled!();
}
buildScope._scheduleBuildFor(element);
// ...
}
BuildScope._scheduleBuildFor
dart
void _scheduleBuildFor(Element element) {
if (!element._inDirtyList) {
_dirtyElements.add(element);
element._inDirtyList = true;
}
if (!_buildScheduled && !_building) {
_buildScheduled = true;
scheduleRebuild?.call();
}
if (_dirtyElementsNeedsResorting != null) {
_dirtyElementsNeedsResorting = true;
}
}
scheduleBuildFor
方法主要执行几个任务
- 当某个
Element
需要重建时,scheduleBuildFor
会把它加入待重建列表_dirtyElements
,并设置标记_inDirtyList
。 - 如果还没有安排重建任务,则通过回调(如
onBuildScheduled
和scheduleRebuild
)通知框架安排一次重建。 - 可能需要对待重建元素列表进行排序
_dirtyElementsNeedsResorting
,以保证重建顺序正确。
scheduleRebuild
在BuildOwner.buildScope
,_buildScope
在_LayoutBuilderElement
中赋值。
_LayoutBuilderElement._scheduleRebuild
dart
@override
RenderAbstractLayoutBuilderMixin<LayoutInfoType, RenderObject> get renderObject =>
super.renderObject as RenderAbstractLayoutBuilderMixin<LayoutInfoType, RenderObject>;
void _scheduleRebuild() {
// 如果已经安排了延迟回调,则直接返回
if (_deferredCallbackScheduled) {
return;
}
// 判断当前调度阶段是否需要延迟布局
final bool deferMarkNeedsLayout = switch (SchedulerBinding.instance.schedulerPhase) {
SchedulerPhase.idle || SchedulerPhase.postFrameCallbacks => true, // 空闲或帧后回调阶段,延迟布局
SchedulerPhase.transientCallbacks ||
SchedulerPhase.midFrameMicrotasks ||
SchedulerPhase.persistentCallbacks => false, // 其他阶段,不延迟
};
if (!deferMarkNeedsLayout) {
// 直接安排布局回调
renderObject.scheduleLayoutCallback();
return;
}
// 标记已安排延迟回调
_deferredCallbackScheduled = true;
// 在下一帧回调中执行
SchedulerBinding.instance.scheduleFrameCallback(_frameCallback);
}
void _frameCallback(Duration timestamp) {
_deferredCallbackScheduled = false;
// This method is only called when the render tree is stable, if the Element
// is deactivated it will never be reincorporated back to the tree.
if (mounted) {
renderObject.scheduleLayoutCallback();
}
}
RenderObject.scheduleLayoutCallback/markNeedsLayout
dart
/// RenderObjectWithLayoutCallbackMixin
// pipeline 标记要重新展示
void scheduleLayoutCallback() {
if (_needsRebuild) {
assert(debugNeedsLayout);
return;
}
_needsRebuild = true;
owner?._nodesNeedingLayout.add(this);
super.markNeedsLayout();
}
void markNeedsLayout() {
if (_needsLayout) {
return;
}
_needsLayout = true;
if (owner case final PipelineOwner owner? when (_isRelayoutBoundary ?? false)) {
// ...
owner._nodesNeedingLayout.add(this);
owner.requestVisualUpdate();
} else if (parent != null) {
markParentNeedsLayout();
}
}
PipelineOwner.requestVisualUpdate
dart
void requestVisualUpdate() {
if (onNeedVisualUpdate != null) {
onNeedVisualUpdate!();
} else {
_manifold?.requestVisualUpdate();
}
}
PipelineManifold.requestVisualUpdate
dart
void requestVisualUpdate() {
_binding.ensureVisualUpdate();
}
SchedulerBinding.ensureVisualUpdate/scheduleFrame
dart
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
void scheduleFrame() {
// 如果已经安排了帧,或者帧不可用,则直接返回
if (_hasScheduledFrame || !framesEnabled) {
return;
}
// 调试模式下打印调用堆栈
assert(() {
if (debugPrintScheduleFrameStacks) {
debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
}
return true;
}());
// 注册帧回调,确保回调已准备好
ensureFrameCallbacksRegistered();
// 通知平台调度一帧,执行下面的方法
// @Native<Void Function()>(symbol: 'PlatformConfigurationNativeApi::ScheduleFrame')
// external static void _scheduleFrame();
platformDispatcher.scheduleFrame();
// 标记已安排帧
_hasScheduledFrame = true;
}
其他
StatefulElement
dart
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
...
_state._element = this;
...
_state._widget = widget;
assert(_state._debugLifecycleState == _StateLifecycle.created);
}
StatefulWidget
对应的Element
是StatefulElement
。
在StatefulElement
中的构造方法中会通过StatefulWidget
的createState
创建State
,State
保存在Element
的_state
属性中,同时将element/widget
本身设置给_state
的_element/_widget
属性。
SchedulerPhase
该枚举其实就是Flutter当前UI帧处理所处的阶段:
- idle 没有在处理帧,可以执行普通任务、定时器、事件回调等
- transientCallbacks 执行一次性帧回调(动画更新、过渡效果等)
- midFrameMicrotasks 处理在上一步中触发的 microtask(例如
Future
的回调) - persistentCallbacks 执行持久帧回调(构建、布局、绘制流程)
- postFrameCallbacks 执行帧结束后的回调(清理、下一帧的任务安排)