前言
有状态组件StatefulWidget中, 更新状态需要调用setState({})方法。比如, 下面程序, 更新_color变量, 需要在setState({})里面。
class TestBuildApp extends StatefulWidget {
const TestBuildApp({Key? key}) : super(key: key);
@override
_TestBuildAppState createState() => _TestBuildAppState();
}
class _TestBuildAppState extends State<TestBuildApp> {
Color _color = Colors.redAccent;
String _title = '6666666666666';
StreamController _streamController = StreamController();
void _incrementCounter() {
setState(() {
_color = Colors.blue;
_title='99999999999999999';
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
primarySwatch: Colors.blue,
),
home: Scaffold(
body: _BuildPage(color: _color, title: _title,),
// body: BuildPage(color: _color, title: _title,),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
),
);
}
}
那么, setState({})是怎样更新状态的呢?setState({})更新状态的原理和执行流程是怎样的呢?带着问题, 我们一起去源码里面学习。
setState
abstract class State<T extends StatefulWidget> with Diagnosticable {
StatefulElement? _element;
/// Whether this [State] object is currently in a tree.
///
/// After creating a [State] object and before calling [initState], the
/// framework "mounts" the [State] object by associating it with a
/// [BuildContext]. The [State] object remains mounted until the framework
/// calls [dispose], after which time the framework will never ask the [State]
/// object to [build] again.
///
/// It is an error to call [setState] unless [mounted] is true.
bool get mounted => _element != null;
@protected
void setState(VoidCallback fn) {
assert(fn != null);
final Object? result = fn() as dynamic;
/// 当前 _element执行markNeedsBuild(), 去
_element!.markNeedsBuild();
}
@protected
Widget build(BuildContext context);
}
setState({})方法中, 很清晰地知道, _element调用markNeedsBuild()方法, 标记当前_element需要更新。我们去_element里面看看。
Element
abstract class Element extends DiagnosticableTree implements BuildContext {
/// Marks the element as dirty and adds it to the global list of widgets to
/// rebuild in the next frame.
///
/// Since it is inefficient to build an element twice in one frame,
/// applications and widgets should be structured so as to only mark
/// widgets dirty during event handlers before the frame begins, not during
/// the build itself.
void markNeedsBuild() {
assert(_lifecycleState != _ElementLifecycle.defunct);
if (_lifecycleState != _ElementLifecycle.active)
return;
assert(owner != null);
assert(_lifecycleState == _ElementLifecycle.active);
if (dirty)
return; /// 返回
_dirty = true; /// 标记为脏
owner!.scheduleBuildFor(this); /// 调用scheduleBuildFor方法, 传入当前Element对象
}
}
markNeedsBuild方法执行了几步关键操作
- 标记当前
Element对象为_dirty脏元素 BuildOwner对象拿到当前Element对象, 调用scheduleBuildFor()方法
接下来, 我们一起看看BuildOwner源码。
BuildOwner
class BuildOwner {
BuildOwner({ this.onBuildScheduled, FocusManager? focusManager }) :
focusManager = focusManager ?? (FocusManager()..registerGlobalHandlers());
/// Called on each build pass when the first buildable element is marked
/// dirty.
VoidCallback? onBuildScheduled;
/// Adds an element to the dirty elements list so that it will be rebuilt
/// when [WidgetsBinding.drawFrame] calls [buildScope].
void scheduleBuildFor(Element element) {
assert(element != null);
assert(element.owner == this);
if (element._inDirtyList) {
_dirtyElementsNeedsResorting = true;
return;
}
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled!(); /// 回调
}
_dirtyElements.add(element); /// 把传进来的element加入脏元素链表
element._inDirtyList = true;
}
}
由scheduleBuildFor()注释: 把一个 element 添加到 _dirtyElements 链表,以便当WidgetsBinding.drawFrame中调用 buildScope 的时候能够重构 element。
我们可以很清晰地知道
- 会去执行
onBuildScheduled!()回调 - 将标记为
_dirty脏元素的Element对象, 加入_dirtyElements列表
onBuildScheduled!()是干嘛的呢? 从源码可知, onBuildScheduled是在BuildOwner类初始化的时候, 传进来的。
BuildOwner在WidgetsBinding的initInstances里初始化。
那么, 我们去到WidgetsBinding里面看看。
WidgetsBinding
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
// Initialization of [_buildOwner] has to be done after
// [super.initInstances] is called, as it requires [ServicesBinding] to
// properly setup the [defaultBinaryMessenger] instance.
/// 初始化_buildOwner对象
_buildOwner = BuildOwner();
/// 配置onBuildScheduled回调
buildOwner!.onBuildScheduled = _handleBuildScheduled;
window.onLocaleChanged = handleLocaleChanged;
window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
assert(() {
FlutterErrorDetails.propertiesTransformers.add(debugTransformDebugCreator);
return true;
}());
}
void _handleBuildScheduled() {
// If we're in the process of building dirty elements, then changes
// should not trigger a new frame.
/// 执行ensureVisualUpdate
ensureVisualUpdate();
}
}
BuildOwner对象执行onBuildScheduled!()回调时, 会去执行WidgetsBinding类中的_handleBuildScheduled()方法_handleBuildScheduled会去执行ensureVisualUpdate方法
那么, ensureVisualUpdate是干嘛的呢?ensureVisualUpdate在SchedulerBinding类中
SchedulerBinding
mixin SchedulerBinding on BindingBase {
/// Schedules a new frame using [scheduleFrame] if this object is not
/// currently producing a frame.
///
/// Calling this method ensures that [handleDrawFrame] will eventually be
/// called, unless it's already in progress.
///
/// This has no effect if [schedulerPhase] is
/// [SchedulerPhase.transientCallbacks] or [SchedulerPhase.midFrameMicrotasks]
/// (because a frame is already being prepared in that case), or
/// [SchedulerPhase.persistentCallbacks] (because a frame is actively being
/// rendered in that case). It will schedule a frame if the [schedulerPhase]
/// is [SchedulerPhase.idle] (in between frames) or
/// [SchedulerPhase.postFrameCallbacks] (after a frame).
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame(); /// 请求新的frame
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
/// If necessary, schedules a new frame by calling
/// [dart:ui.PlatformDispatcher.scheduleFrame].
///
/// After this is called, the engine will (eventually) call
/// [handleBeginFrame]. (This call might be delayed, e.g. if the device's
/// screen is turned off it will typically be delayed until the screen is on
/// and the application is visible.) Calling this during a frame forces
/// another frame to be scheduled, even if the current frame has not yet
/// completed.
///
/// Scheduled frames are serviced when triggered by a "Vsync" signal provided
/// by the operating system. The "Vsync" signal, or vertical synchronization
/// signal, was historically related to the display refresh, at a time when
/// hardware physically moved a beam of electrons vertically between updates
/// of the display. The operation of contemporary hardware is somewhat more
/// subtle and complicated, but the conceptual "Vsync" refresh signal continue
/// to be used to indicate when applications should update their rendering.
///
/// To have a stack trace printed to the console any time this function
/// schedules a frame, set [debugPrintScheduleFrameStacks] to true.
///
/// See also:
///
/// * [scheduleForcedFrame], which ignores the [lifecycleState] when
/// scheduling a frame.
/// * [scheduleWarmUpFrame], which ignores the "Vsync" signal entirely and
/// triggers a frame immediately.
/// 请求新的frame
void scheduleFrame() {
if (_hasScheduledFrame || !framesEnabled)
return;
assert(() {
if (debugPrintScheduleFrameStacks)
debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
return true;
}());
/// 确保帧渲染的回调已经被注册
ensureFrameCallbacksRegistered();
/// window调度帧
window.scheduleFrame();
_hasScheduledFrame = true;
}
/// Ensures callbacks for [PlatformDispatcher.onBeginFrame] and
/// [PlatformDispatcher.onDrawFrame] are registered.
@protected
void ensureFrameCallbacksRegistered() {
window.onBeginFrame ??= _handleBeginFrame;
window.onDrawFrame ??= _handleDrawFrame;
}
}
ensureVisualUpdate方法中, 根据不同的schedulerPhase枚举值, 做对应的处理。
当 schedulerPhase为SchedulerPhase.idle、SchedulerPhase.postFrameCallbacks时调用scheduleFrame()方法
schedulerPhase枚举值解释如下
SchedulerPhase
Flutter 应用执行过程简单来讲分为 idle 和 frame 两种状态,idle 状态代表没有 frame 处理,如果应用状态改变需要刷新 UI,则需要通过scheduleFrame()去请求新的 frame,当 frame 到来时,就进入了frame状态,整个Flutter应用生命周期就是在 idle 和 frame 两种状态间切换。
当有新的 frame 到来时,开始调用 SchedulerBinding.handleDrawFrame 来处理 frame,具体处理过程就是依次执行四个任务队列:transientCallbacks、midFrameMicrotasks、persistentCallbacks、postFrameCallbacks,当四个任务队列执行完毕后当前 frame 结束。
综上,Flutter 将整个生命周期分为五种状态,通过 SchedulerPhase 枚举类来表示它们:
enum SchedulerPhase {
/// 空闲状态,并没有 frame 在处理。这种状态代表页面未发生变化,并不需要重新渲染。
/// 如果页面发生变化,需要调用`scheduleFrame()`来请求 frame。
/// 注意,空闲状态只是指没有 frame 在处理,通常微任务、定时器回调或者用户事件回调都
/// 可能被执行,比如监听了tap事件,用户点击后我们 onTap 回调就是在idle阶段被执行的。
idle,
/// 执行”临时“回调任务,”临时“回调任务只能被执行一次,执行后会被移出”临时“任务队列。
/// 典型的代表就是动画回调会在该阶段执行。
transientCallbacks,
/// 在执行临时任务时可能会产生一些新的微任务,比如在执行第一个临时任务时创建了一个
/// Future,且这个 Future 在所有临时任务执行完毕前就已经 resolve 了,这中情况
/// Future 的回调将在[midFrameMicrotasks]阶段执行
midFrameMicrotasks,
/// 执行一些持久的任务(每一个frame都要执行的任务),比如渲染管线(构建、布局、绘制)
/// 就是在该任务队列中执行的.
persistentCallbacks,
/// 在当前 frame 在结束之前将会执行 postFrameCallbacks,通常进行一些清理工作和
/// 请求新的 frame。
postFrameCallbacks,
}
下面, 我们再回到scheduleFrame()看看。
scheduleFrame()
mixin SchedulerBinding on BindingBase {
/// If necessary, schedules a new frame by calling
/// [dart:ui.PlatformDispatcher.scheduleFrame].
///
/// After this is called, the engine will (eventually) call
/// [handleBeginFrame]. (This call might be delayed, e.g. if the device's
/// screen is turned off it will typically be delayed until the screen is on
/// and the application is visible.) Calling this during a frame forces
/// another frame to be scheduled, even if the current frame has not yet
/// completed.
///
/// Scheduled frames are serviced when triggered by a "Vsync" signal provided
/// by the operating system. The "Vsync" signal, or vertical synchronization
/// signal, was historically related to the display refresh, at a time when
/// hardware physically moved a beam of electrons vertically between updates
/// of the display. The operation of contemporary hardware is somewhat more
/// subtle and complicated, but the conceptual "Vsync" refresh signal continue
/// to be used to indicate when applications should update their rendering.
///
/// To have a stack trace printed to the console any time this function
/// schedules a frame, set [debugPrintScheduleFrameStacks] to true.
///
/// See also:
///
/// * [scheduleForcedFrame], which ignores the [lifecycleState] when
/// scheduling a frame.
/// * [scheduleWarmUpFrame], which ignores the "Vsync" signal entirely and
/// triggers a frame immediately.
/// 请求新的frame
void scheduleFrame() {
if (_hasScheduledFrame || !framesEnabled)
return;
/// 确保帧渲染的回调已经被注册
ensureFrameCallbacksRegistered();
/// window调度帧
window.scheduleFrame();
_hasScheduledFrame = true;
}
/// Ensures callbacks for [PlatformDispatcher.onBeginFrame] and
/// [PlatformDispatcher.onDrawFrame] are registered.
@protected
void ensureFrameCallbacksRegistered() {
window.onBeginFrame ??= _handleBeginFrame;
window.onDrawFrame ??= _handleDrawFrame;
}
}
ensureFrameCallbacksRegistered
/// Ensures callbacks for [PlatformDispatcher.onBeginFrame] and
/// [PlatformDispatcher.onDrawFrame] are registered.
@protected
void ensureFrameCallbacksRegistered() {
window.onBeginFrame ??= _handleBeginFrame;
window.onDrawFrame ??= _handleDrawFrame;
}
ensureFrameCallbacksRegistered方法中, 配置了_handleBeginFrame、_handleDrawFrame两个回调。
_handleBeginFrame
void _handleBeginFrame(Duration rawTimeStamp) {
if (_warmUpFrame) {
// "begin frame" and "draw frame" must strictly alternate. Therefore
// _rescheduleAfterWarmUpFrame cannot possibly be true here as it is
// reset by _handleDrawFrame.
assert(!_rescheduleAfterWarmUpFrame);
_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;
assert(() {
_debugFrameNumber += 1;
if (debugPrintBeginFrameBanner || debugPrintEndFrameBanner) {
final StringBuffer frameTimeStampDescription = StringBuffer();
if (rawTimeStamp != null) {
_debugDescribeTimeStamp(_currentFrameTimeStamp!, frameTimeStampDescription);
} else {
frameTimeStampDescription.write('(warm-up frame)');
}
_debugBanner = '▄▄▄▄▄▄▄▄ Frame ${_debugFrameNumber.toString().padRight(7)} ${frameTimeStampDescription.toString().padLeft(18)} ▄▄▄▄▄▄▄▄';
if (debugPrintBeginFrameBanner)
debugPrint(_debugBanner);
}
return true;
}());
assert(schedulerPhase == SchedulerPhase.idle);
/// 此时阶段等于SchedulerPhase.idle;
_hasScheduledFrame = false;
try {
// TRANSIENT FRAME CALLBACKS
_frameTimelineTask?.start('Animate', arguments: timelineArgumentsIndicatingLandmarkEvent);
/// 执行动画的回调方法 schedulerPhase.transientCallbacks;
_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.midFrameMicrotasks;
_schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
}
主要就是遍历_transientCallbacks,执行相应的Animate操作, 可通过scheduleFrameCallback()/cancelFrameCallbackWithId()来完成添加和删除成员
最后将调度状态更新到SchedulerPhase.midFrameMicrotasks
_handleDrawFrame
void _handleDrawFrame() {
if (_rescheduleAfterWarmUpFrame) {
_rescheduleAfterWarmUpFrame = false;
// Reschedule in a post-frame callback to allow the draw-frame phase of
// the warm-up frame to finish.
addPostFrameCallback((Duration timeStamp) {
// Force an engine frame.
//
// We need to reset _hasScheduledFrame here because we cancelled the
// original engine frame, and therefore did not run handleBeginFrame
// who is responsible for resetting it. So if a frame callback set this
// to true in the "begin frame" part of the warm-up frame, it will
// still be true here and cause us to skip scheduling an engine frame.
_hasScheduledFrame = false;
scheduleFrame();
});
return;
}
handleDrawFrame();
}
_handleDrawFrame会去执行handleDrawFrame方法。
根据注释, [handleBeginFrame]执行后, 会立即执行handleDrawFrame方法。
handleDrawFrame
/// Called by the engine to produce a new frame.
///
/// This method is called immediately after [handleBeginFrame]. It calls all
/// the callbacks registered by [addPersistentFrameCallback], which typically
/// drive the rendering pipeline, and then calls the callbacks registered by
/// [addPostFrameCallback].
///
/// See [handleBeginFrame] for a discussion about debugging hooks that may be
/// useful when working with frame callbacks.
void handleDrawFrame() {
/// 确保当前状态是 SchedulerPhase.midFrameMicrotasks
assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
/// 动画结束
_frameTimelineTask?.finish(); // end the "Animate" phase
try {
// PERSISTENT FRAME CALLBACKS
/// 执行PERSISTENT FRAME回调, 主要包括build\layout\draw流程
/// SchedulerPhase.persistentCallbacks;
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
/// SchedulerPhase.postFrameCallbacks
/// 执行POST-FRAME回调, 主要是状态清理,准备调度下一帧frame绘制请求
// POST-FRAME CALLBACKS
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List<FrameCallback> localPostFrameCallbacks =
List<FrameCallback>.from(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
} finally {
/// 最后, 恢复成 SchedulerPhase.idle 空闲状态
_schedulerPhase = SchedulerPhase.idle;
/// 标识结束”Frame“阶段
_frameTimelineTask?.finish(); // end the Frame
assert(() {
if (debugPrintEndFrameBanner)
debugPrint('▀' * _debugBanner!.length);
_debugBanner = null;
return true;
}());
_currentFrameTimeStamp = null;
}
}
/ Calls the given [callback] with [timestamp] as argument.
//
// Wraps the callback in a try/catch and forwards any error to
// [debugSchedulerExceptionHandler], if set. If not set, then simply prints
// the error.
@pragma('vm:notify-debugger-on-exception')
void _invokeFrameCallback(FrameCallback callback, Duration timeStamp, [ StackTrace? callbackStack ]) {
assert(callback != null);
assert(_FrameCallbackEntry.debugCurrentCallbackStack == null);
assert(() {
_FrameCallbackEntry.debugCurrentCallbackStack = callbackStack;
return true;
}());
try {
callback(timeStamp);
} catch (exception, exceptionStack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: exceptionStack,
library: 'scheduler library',
context: ErrorDescription('during a scheduler callback'),
informationCollector: (callbackStack == null) ? null : () sync* {
yield DiagnosticsStackTrace(
'\nThis exception was thrown in the context of a scheduler callback. '
'When the scheduler callback was _registered_ (as opposed to when the '
'exception was thrown), this was the stack',
callbackStack,
);
},
));
}
assert(() {
_FrameCallbackEntry.debugCurrentCallbackStack = null;
return true;
}());
}
该方法主要功能:
- 遍历
_persistentCallbacks,执行相应的回调方法,可通过addPersistentFrameCallback()注册,一旦注册后不可移除,后续每一次frame回调都会执行 _persistentCallbacks主要包括build\layout\draw流程- 遍历
_postFrameCallbacks,执行相应的回调方法,可通过addPostFrameCallback()注册,handleDrawFrame()执行完成后会清空_postFrameCallbacks内容 _postFrameCallbacks主要是状态清理,准备调度下一帧frame绘制请求
探究源码到这里, 我们心里多了疑惑。handleDrawFrame是去绘制帧, 绘制帧应该在RenderObject类里呀。handleDrawFrame只是循环执行了_persistentCallbacks、_postFrameCallbacks里面的方法。那么, _persistentCallbacks、_postFrameCallbacks数组里的值, 从哪里添加的呢?SchedulerBinding类又是怎样跟绘制绑定类RendererBinding关联的呢?
答案是有的。
runApp启动整个flutter程序, 加载根节点的时候, RendererBinding初始化的时候, 已经有了交代。
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,
);
window
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
initRenderView();
_handleSemanticsEnabledChanged();
assert(renderView != null);
/// 初始化的时候, 执行addPersistentFrameCallback
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
if (kIsWeb) {
addPostFrameCallback(_handleWebFirstFrame);
}
}
void _handlePersistentFrameCallback(Duration timeStamp) {
/// 执行绘制帧
drawFrame();
_scheduleMouseTrackerUpdate();
}
}
RendererBinding类初始化的时候, 加载一个持久化绘制帧任务_handlePersistentFrameCallback回调, 并存储到SchedulerBinding类的_persistentCallbacks数组里面。等到合适的时机, 去_persistentCallbacks数组里面取出去, 并执行。合适的时机有哪些呢?
- runApp(Widget app)中的scheduleWarmUpFrame()
- setSate({})
我们可以在demo, debug模式, 跟踪具体流程。
以上配置好ensureFrameCallbacksRegistered()回调后。真正激活ensureFrameCallbacksRegistered()回调并响应绘制流程, 还需要关键一步, 那就是调用window.scheduleFrame()。这样, 就激活程序, 去RendererBinding绑定类绘制了。
我们一起学习window.scheduleFrame()
window.scheduleFrame()
void scheduleFrame() => platformDispatcher.scheduleFrame();
platformDispatcher执行scheduleFrame()
void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';
上面程序, 最终会执行到引擎层面PlatformConfiguration_scheduleFrame
c++ 引擎
void ScheduleFrame(Dart_NativeArguments args) {
// 看下方 RuntimeController::ScheduleFrame
UIDartState::Current()->window()->client()->ScheduleFrame();
}
通过RegisterNatives()完成native方法的注册,“Window_scheduleFrame”所对应的native方法如上所示。
Engine::ScheduleFrame
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame(); // 看下面Engine::ScheduleFrame
}
这里推荐查看袁辉辉大佬的:Flutter渲染机制—UI线程 文中小节[2.1]介绍Engine::ScheduleFrame()经过层层调用,最终会注册Vsync回调。 等待下一次vsync信号的到来, 然后再经过层层调用最终会调用到Window::BeginFrame()。
Window::BeginFrame
void Window::BeginFrame(fml::TimePoint frameTime) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds();
DartInvokeField(library_.value(), "_beginFrame",
{
Dart_NewInteger(microseconds),
});
//执行MicroTask
UIDartState::Current()->FlushMicrotasksNow();
DartInvokeField(library_.value(), "_drawFrame", {});
}
Window::BeginFrame()过程主要工作:
- 执行_beginFrame
- 执行FlushMicrotasksNow
- 执行_drawFrame 可见,Microtask位于beginFrame和drawFrame之间,那么Microtask的耗时会影响ui绘制过程。
可以清晰地知道, window.scheduleFrame()执行后, window.onBeginFrame和window.onDrawFrame将紧接着会在合适时机被调用。
总结
可见,setState()过程主要工作是记录所有的脏元素,添加到BuildOwner对象的_dirtyElements成员变量,然后调用scheduleFrame来注册Vsync回调。 当下一次vsync信号的到来时会执行handleBeginFrame()和handleDrawFrame()来更新UI。
参考资料
Flutter 学习之旅(三十九) Flutter RenderObjcet(一)layout布局过程