公告

微信

欢迎大家私信交流

Skip to content

setState流程分析

Flutter setState流程分析

一个匿名函数setState的执行,背后竟然涉及State → Element → BuildOwner → PipelineOwner → Renderer一套流程。

看看咋回事~

流程简析

StatefulWidget有对应的State对象

StateUI树上的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会调用ownerscheduleBuildFor方法,将该element标记为dirty,并且将element加入到一个全局的表示需要更新的Element列表中。

ownerBuildOwner对象。

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方法主要执行几个任务

  1. 当某个Element需要重建时,scheduleBuildFor会把它加入待重建列表_dirtyElements,并设置标记_inDirtyList
  2. 如果还没有安排重建任务,则通过回调(如onBuildScheduledscheduleRebuild)通知框架安排一次重建。
  3. 可能需要对待重建元素列表进行排序_dirtyElementsNeedsResorting,以保证重建顺序正确。

scheduleRebuildBuildOwner.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对应的ElementStatefulElement

StatefulElement中的构造方法中会通过StatefulWidgetcreateState创建StateState保存在Element_state属性中,同时将element/widget本身设置给_state_element/_widget属性。

SchedulerPhase

该枚举其实就是Flutter当前UI帧处理所处的阶段

  1. idle 没有在处理帧,可以执行普通任务、定时器、事件回调等
  2. transientCallbacks 执行一次性帧回调(动画更新、过渡效果等)
  3. midFrameMicrotasks 处理在上一步中触发的 microtask(例如 Future 的回调)
  4. persistentCallbacks 执行持久帧回调(构建、布局、绘制流程)
  5. postFrameCallbacks 执行帧结束后的回调(清理、下一帧的任务安排)

上次更新于: