Flutter中setState更新机制探索
简述
有状态组件
StatefulWidget更新状态调用setState(() {})函数实现数据更新
setState内部实现
精简部分代码
abstract class State<T extends StatefulWidget> with Diagnosticable {
StatefulElement? _element;
bool get mounted => _element != null;
@protected
void setState(VoidCallback fn) {
final Object? result = fn() as dynamic;
/// _element执行 markNeedsBuild
_element!.markNeedsBuild();
}
通过上面代码可以看到setState(() {})函数中主要是_element执行markNeedsBuild()
markNeedsBuild
abstract class Element extends DiagnosticableTree implements BuildContext {
void markNeedsBuild() {
if (_lifecycleState != _ElementLifecycle.active)
return;
if (dirty)
return;
_dirty = true;
owner!.scheduleBuildFor(this);
}
markNeedsBuild函数执行关键几步:
-
判断
_lifecycleState是否是_ElementLifecycle.active状态 -
当前元素是否标记为脏
-
BuildOwner对象执行scheduleBuildFor函数,并传入当前元素Element
scheduleBuildFor
class BuildOwner {
void scheduleBuildFor(Element element) {
if (element._inDirtyList) {
_dirtyElementsNeedsResorting = true;
return;
}
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled!();
}
_dirtyElements.add(element);
element._inDirtyList = true;
}
}
scheduleBuildFor把当前element加入_dirtyElements列表里面 并且标记当前元素的_inDirtyList为true- 执行
onBuildScheduled回调 - onBuildScheduled 回调是在BuildOwner初始化的时候传进来的
onBuildScheduled()
onBuildScheduled()回调是在 WidgetsBinding中实现的
mixin WidgetsBinding on BindingBase, ... {
_buildOwner = BuildOwner();
buildOwner!.onBuildScheduled = _handleBuildScheduled;
}
- BuildOwner对象执行onBuildScheduled!()回调时, 会去执行WidgetsBinding类中的
_handleBuildScheduled()方法
_handleBuildScheduled()
void _handleBuildScheduled() {
ensureVisualUpdate();
}
_handleBuildScheduled函数执行ensureVisualUpdate函数
ensureVisualUpdate
ensureVisualUpdate在SchedulerBinding类中
mixin SchedulerBinding on BindingBase {
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
}
scheduleFrame()
void scheduleFrame() {
if (_hasScheduledFrame || !framesEnabled)
return;
ensureFrameCallbacksRegistered();
platformDispatcher.scheduleFrame();
_hasScheduledFrame = true;
}
scheduleFrame 函数里面调用了下面两个函数
ensureFrameCallbacksRegistered函数platformDispatcher.scheduleFrame()函数;
platformDispatcher.scheduleFrame()
void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';
ensureFrameCallbacksRegistered();
@protected
void ensureFrameCallbacksRegistered() {
platformDispatcher.onBeginFrame ??= _handleBeginFrame;
platformDispatcher.onDrawFrame ??= _handleDrawFrame;
}
ensureFrameCallbacksRegistered 方法中给平台调度器设置了两个回调_handleBeginFrame 与 _handleDrawFrame
_handleBeginFrame
void _handleBeginFrame(Duration rawTimeStamp) {
if (_warmUpFrame) {
_rescheduleAfterWarmUpFrame = true;
return;
}
handleBeginFrame(rawTimeStamp);
}
_handleBeginFrame 会执行 handleBeginFrame方法
handleBeginFrame
void handleBeginFrame(Duration? rawTimeStamp) {
_frameTimelineTask?.start('Frame', arguments: timelineArgumentsIndicatingLandmarkEvent);
_firstRawTimeStampInEpoch ??= rawTimeStamp;
_currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
if (rawTimeStamp != null)
_lastRawTimeStamp = rawTimeStamp;
_hasScheduledFrame = false;
try {
// TRANSIENT FRAME CALLBACKS
_frameTimelineTask?.start('Animate', arguments: timelineArgumentsIndicatingLandmarkEvent);
_schedulerPhase = SchedulerPhase.transientCallbacks;
final Map<int, _FrameCallbackEntry> callbacks = _transientCallbacks;
_transientCallbacks = <int, _FrameCallbackEntry>{};
callbacks.forEach((int id, _FrameCallbackEntry callbackEntry) {
if (!_removedIds.contains(id))
_invokeFrameCallback(callbackEntry.callback, _currentFrameTimeStamp!, callbackEntry.debugStack);
});
_removedIds.clear();
} finally {
_schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
}
handleBeginFrame 执行操作
- _frameTimelineTask执行
frame动画 - _frameTimelineTask执行
Animate动画 - 遍历
_transientCallbacks回调 - 最后将_schedulerPhase状态更新为
SchedulerPhase.midFrameMicrotasks
_handleDrawFrame()
void _handleDrawFrame() {
if (_rescheduleAfterWarmUpFrame) {
_rescheduleAfterWarmUpFrame = false;
addPostFrameCallback((Duration timeStamp) {
_hasScheduledFrame = false;
scheduleFrame();
});
return;
}
handleDrawFrame();
}
_handleDrawFrame执行handleDrawFrame方法
handleDrawFrame()
void handleDrawFrame() {
assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
_frameTimelineTask?.finish();
try {
// PERSISTENT FRAME CALLBACKS
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
// POST-FRAME CALLBACKS
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List<FrameCallback> localPostFrameCallbacks =
List<FrameCallback>.of(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
} finally {
_schedulerPhase = SchedulerPhase.idle;
_frameTimelineTask?.finish(); // end the Frame
assert(() {
if (debugPrintEndFrameBanner)
debugPrint('▀' * _debugBanner!.length);
_debugBanner = null;
return true;
}());
_currentFrameTimeStamp = null;
}
}
该方法主要执行操作
-
_frameTimelineTask结束动画操作 -
遍历
persistentCallbacks回调,执行_invokeFrameCallback -
遍历
_postFrameCallbacks执行_invokeFrameCallback,并且执行清空操作_postFrameCallbacks.clear(); -
最后
_schedulerPhase、_frameTimelineTask相关状态还原,准备下一次更新
_persistentCallbacks 、_postFrameCallbacks 里面的方法在什么地方添加的
RendererBinding
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
@override
void initInstances() {
super.initInstances();
_instance = this;
_pipelineOwner = PipelineOwner(
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
platformDispatcher
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
initRenderView();
_handleSemanticsEnabledChanged();
assert(renderView != null);
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
if (kIsWeb) {
addPostFrameCallback(_handleWebFirstFrame);
}
}
void _handlePersistentFrameCallback(Duration timeStamp) {
/// 执行绘制
drawFrame();
_scheduleMouseTrackerUpdate();
}
- 可以看到 初始化的时候执行
addPersistentFrameCallback回调 - 将这个回调存储到
SchedulerBinding类的_persistentCallbacks数组里面,等到用的时候取出来去执行
合适时机有哪些
- runApp(Widget app)中的scheduleWarmUpFrame()
- setSate({})
总结
setState()过程主要工作是记录所有的脏元素,添加到BuildOwner对象的_dirtyElements成员变量,然后调用scheduleFrame来执行handleBeginFrame()和handleDrawFrame()更新UI