上文 Flutter 框架简介 简单介绍了框架的边界和入口,这篇文章主要介绍下 Flutter 框架执行流程。
1. SchedulerPhase
SchedulerPhase 是个枚举类,标识框架调度执行的各个阶段。
enum SchedulerPhase {
// 空闲阶段,此阶段没有帧调度。会执行 Tasks,microtasks,Timer callbacks 等
idle,
// 由 SchedulerBinding.scheduleFrameCallback 调度,动画执行 _tick 过程在这个阶段执行
transientCallbacks,
// 执行上一个阶段调度的 microtasks,如 Future
midFrameMicrotasks,
// 由 SchedulerBinding.addPersisitentFrameCallback 调度。build/layout/paint 过程在这里执行
persistentCallbacks,
// 由 SchedulerBinding.addPostFrameCallback 调度。通常执行清理和下一帧调度相关工作
postFrameCallbacks,
}
2. handleBeginFrame
window 的 onBeginFrame 由 SchedulerBinding.handleBeginFrame 处理。
mixin SchedulerBinding on BindingBase {
...
void handleBeginFrame(Duration? rawTimeStamp) {
...
assert(schedulerPhase == SchedulerPhase.idle);
...
try {
// TRANSIENT FRAME CALLBACKS
Timeline.startSync('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 在 SchedulerPhase.transientCallbacks 阶段,执行了 _transientCallbacks。
Ticker 在 _tick 方法中间接调用 SchedulerBinding.scheduleFrameCallback 将 _tick 加入 transientCallbacks 中,在这里会执行。
3. handleDrawFrame
window 的 onDrawFrame 由 SchedulerBinding.handleDrawFrame 处理。
void handleDrawFrame() {
...
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>.from(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
} finally {
_schedulerPhase = SchedulerPhase.idle;
}
}
在 handleDrawFrame 方法中,先后执行了 _persistentCallbacks 和 _postFrameCallbacks。
_persistentCallbacks 中,添加了 RendererBinding 在初始化 initInstances 时添加的 _handlePersistentFrameCallback。
RendererBinding._handlePersistentFrameCallback
void _handlePersistentFrameCallback(Duration timeStamp) {
drawFrame();
_scheduleMouseTrackerUpdate();
}
这里调用了 drawFrame。注意,这里的 drawFrame 并没有直接调用自己的 drawFrame,而是调用了 WidgetsBinding.drawFrame。
@override
void drawFrame() {
...
try {
if (renderViewElement != null)
buildOwner.buildScope(renderViewElement);
super.drawFrame();
buildOwner.finalizeTree();
}
...
}
可以看到,这里调用了 buildOwner.buildScope 方法,执行 build 构建过程,最后保存树(Widget)的状态。其中 super.drawFrame 才是调用了 RendererBinding.drawFrame。
RenderBinding.drawFrame
@protected
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
if (sendFramesToEngine) {
renderView.compositeFrame(); // this sends the bits to the GPU
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
_firstFrameSent = true;
}
}
这里由 pipelineOwner 对象完成 layout、paint、composition 过程。
最后说一下 _postFrameCallbacks,_postFrameCallbacks 在当前帧结束时调用,这个回调只会执行一次,你可以在这个回调中添加需要等待页面渲染结束才执行的某些操作。