Flutter Framework层UI绘制的入口(一)

原创
2021/05/09 20:08
阅读数 19

本文记录自己学习 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 {  @override  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]调用,当需要布置和绘制框架时,引擎会自动调用该方法。@override  void drawFrame() {    ...    try {      if (renderViewElement != null)        buildOwner.buildScope(renderViewElement);      super.drawFrame();      buildOwner.finalizeTree();    } finally {      ...    }    ...  }

由此可见,drawFrame()方法是 Flutter 不断 build(构建控件树),layout(布局), paint(绘制)和 composite(合成)的入口。


本文分享自微信公众号 - Flutter学习簿(gh_d739155d3b2c)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部