Flutter Framework层UI绘制的入口(一)
本文记录自己学习 Flutter 绘制所见源码,并不是全面详细的解析 Blog。
Flutter 源码环境:1.22.1
Flutter 官方提供一张 Vsync 信号使 UI 线程和 GPU 线程相互协调渲染界面,如图所示:
由上图可知,UI 线程只负责 Dart 层的视图数据的处理绘制,并将处理后的尽快数据提供给 GPU。
Flutter Framework 绘制层
初始化注册以及响应
在 Flutter 中,对 Vsync 信号的注册,处理响应 Vsync 到来的过程中,底层会调用到 window.onBeginFrame()和 onDrawFrame()这两个方法,对应 Dart 层就_onBeginFrame,_onDrawFrame。
1.2 window
sky_engine/lib/ui/window.dart
class Window {
Window._() {
...
}
FrameCallback? get onBeginFrame => _onBeginFrame;
FrameCallback? _onBeginFrame;
set onBeginFrame(FrameCallback? callback) {
_onBeginFrame = callback;
...
}
VoidCallback? get onDrawFrame => _onDrawFrame;
VoidCallback? _onDrawFrame;
Zone _onDrawFrameZone = Zone.root;
set onDrawFrame(VoidCallback? callback) {
_onDrawFrame = callback;
...
}
}
onBeginFrame,onDrawFrame 实际持有者是_onBeginFrame,_onDrawFrame。那它又是怎么被初始化赋值的呢?
1.1 初始化
我们从入口方法 main(),一步步来看。
1.1.1 main()
void main() {
runApp(MyApp());
}
1.1.2 runApp()
flutter/lib/src/widgets/binding.dart
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
1.1.3 scheduleAttachRootWidget()
flutter/lib/src/widgets/binding.dart
@protected
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
...
void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement<RenderBox>);
}
可见,在 attachRootWidget 的过程中,会实例化一个_renderViewElement,并把应用传过来的 rootWidget 作为根节点加入树中。
1.1.4 attachToRenderTree()
flutter/lib/src/widgets/binding.dart
RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T> element ]) {
if (element == null) {
owner.lockState(() {
element = createElement();
assert(element != null);
element.assignOwner(owner);
});
owner.buildScope(element, () {
element.mount(null, null);
});
// This is most likely the first time the framework is ready to produce
// a frame. Ensure that we are asked for one.
SchedulerBinding.instance.ensureVisualUpdate();
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element;
}
程序第一次启动 element 是空的,那么会创建一个新的,调用 ensureVisualUpdate(),否则标识更新。
再继续看SchedulerBinding.instance.ensureVisualUpdate()方法。
flutter/lib/src/scheduler/binding.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() {
...
//确保有注册监听回调
ensureFrameCallbacksRegistered();
//注册信号
window.scheduleFrame();
_hasScheduledFrame = true;
}
@protected
void ensureFrameCallbacksRegistered()
//初始化赋值
window.onBeginFrame ??= _handleBeginFrame;
window.onDrawFrame ??= _handleDrawFrame;
}
终于在 ensureFrameCallbacksRegistered() 方法中看到了对_onBeginFrame,_onDrawFrame 的赋值。
继续看看_handleBeginFrame,_handleDrawFrame 都做了些什么?
1.3 _handleBeginFrame
flutter/lib/src/scheduler/binding.dart
void _handleBeginFrame(Duration rawTimeStamp) {
if (_warmUpFrame) {
assert(!_ignoreNextEngineDrawFrame);
_ignoreNextEngineDrawFrame = true;
return;
}
//调用 1.3.1
handleBeginFrame(rawTimeStamp);
}
1.3.1 handleBeginFrame
flutter/lib/src/scheduler/binding.dart
void handleBeginFrame(Duration? rawTimeStamp) {
Timeline.startSync('Frame', arguments: timelineArgumentsIndicatingLandmarkEvent);
_firstRawTimeStampInEpoch ??= rawTimeStamp;
_currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
if (rawTimeStamp != null)
_lastRawTimeStamp = rawTimeStamp;
...
//此时阶段等于SchedulerPhase.idle;因为初始值就是idle
_hasScheduledFrame = false;
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;
}
}
该方法主要就是 遍历_transientCallbacks,执行对应的回调方法,_transientCallbacks 链表可以通过scheduleFrameCallback()/cancelFrameCallbackWithId()方法来添加和删除回调。
1.4 _handleDrawFrame
flutter/lib/src/scheduler/binding.dart
void _handleDrawFrame() {
if (_ignoreNextEngineDrawFrame) {
_ignoreNextEngineDrawFrame = false;
return;
}
//调用1.4.1
handleDrawFrame();
}
1.4.1 handleDrawFrame
flutter/lib/src/scheduler/binding.dart
void handleDrawFrame() {
assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
Timeline.finishSync(); // end the "Animate" phase 标识结束"Animate"阶段
try {
// PERSISTENT FRAME CALLBACKS 执行PERSISTENT FRAME回调
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
//调用 1.4.2
_invokeFrameCallback(callback, _currentFrameTimeStamp!);
// POST-FRAME CALLBACKS 执行POST-FRAME回调
_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;
Timeline.finishSync(); // end the Frame 标识结束”Frame“阶段
_currentFrameTimeStamp = null;
}
}
该方法的主要功能:
遍历_persistentCallbacks,执行相应的回调方法,_persistentCallbacks 通过 addPersistentFrameCallback()添加成员,一旦注册后不可移除,后续每一次 frame 回调都会执行。
遍历_postFrameCallbacks,执行相应的回调方法,_postFrameCallbacks 通过 addPostFrameCallback()添加成员,handleDrawFrame()执行完成后会清空_postFrameCallbacks 链表。
1.4.2 _invokeFrameCallback
flutter/lib/src/scheduler/binding.dart
void _invokeFrameCallback(FrameCallback callback, Duration timeStamp, [ StackTrace? callbackStack ]) {
...
try {
//回调
callback(timeStamp);
} catch (exception, exceptionStack) {
...
}
}
}
callback 执行的是 _persistentCallbacks 或者_postFrameCallbacks 成员中的回调。看看这些回调是怎么在初始化的时候加进去的。
1.5 WidgetsBinding.initInstances
在调用 runApp 后会调用到 ensureInitialized()获取 WidgetsBinding 的实例对象 _instance,
_instance 在 initInstances() 中得以初始化。
flutter/lib/src/widgets/binding.dart
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
//调用1.5.1
super.initInstances();
_instance = this;
//其他初始化
...
}
}
runApp 过程会有 WidgetsFlutterBinding 初始化过程,调用WidgetsBinding 的 initInstances(),因为 WidgetsBinding 混入(mixin) RendererBinding,所以 super.initInstances()也会调用到 RendererBinding 的 initInstances()方法中。
1.5.1 RendererBinding
flutter/lib/src/rendering/binding.dart
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
void initInstances() {
super.initInstances();
_instance = this;
//初始化_pipelineOwner
_pipelineOwner = PipelineOwner(
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
//注册一些回调
window
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
//初始化renderView
initRenderView();
_handleSemanticsEnabledChanged();
assert(renderView != null);
//终于在这看到了对_persistentCallbacks 的注册赋值
//调用1.5.2
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
}
void _handlePersistentFrameCallback(Duration timeStamp) {
//调用 1.6
drawFrame();
//该方法添加了_postFrameCallbacks链表回调成员。
_scheduleMouseTrackerUpdate();
}
}
1.5.2 addPersistentFrameCallback
flutter/lib/src/rendering/binding.dart
void addPersistentFrameCallback(FrameCallback callback) {
//添加回调
_persistentCallbacks.add(callback);
}
1.6 drawFrame
/flutter/lib/src/widgets/binding.dart
//此方法由[handleDrawFrame]调用,当需要布置和绘制框架时,引擎会自动调用该方法。
void drawFrame() {
...
try {
if (renderViewElement != null)
buildOwner.buildScope(renderViewElement);
super.drawFrame();
buildOwner.finalizeTree();
} finally {
...
}
...
}