https://book.flutterchina.club/chapter14/flutter_app_startup.html

  1. setState(() {
  2. ...
  3. })
  • _element.markNeedsBuild() :将元素标记为脏,并将其添加到全局窗口小部件列表中,以便在下一帧中重建。
  • owner.scheduleBuildFor(this) :将元素添加到脏元素列表 _dirtyElements 中,以便在[WidgetsBinding.drawFrame]调用[buildScope]时重建它。
  • onBuildScheduled() . flutter/packages/flutter/lib/src/widgets/framework.dart
  • ensureVisualUpdate() . flutter/packages/flutter/lib/src/widgets/binding.dart
  • scheduleFrame() . flutter/packages/flutter/lib/src/scheduler/binding.dart
  • window.scheduleFrame() 进入 native code

https://sourcegraph.com/github.com/flutter/engine/-/blob/lib/ui/window/window.cc#L375

  1. void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
  2. natives->Register({
  3. {"Window_defaultRouteName", DefaultRouteName, 1, true},
  4. {"Window_scheduleFrame", ScheduleFrame, 1, true},
  5. {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
  6. {"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
  7. {"Window_render", Render, 2, true},
  8. {"Window_updateSemantics", UpdateSemantics, 2, true},
  9. {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
  10. {"Window_reportUnhandledException", ReportUnhandledException, 2, true},
  11. {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true},
  12. });
  13. }

Engine::ScheduleFrame:https://sourcegraph.com/github.com/flutter/engine@master/-/blob/shell/common/engine.cc#L414
RequestFramehttps://sourcegraph.com/github.com/flutter/engine@master/-/blob/shell/common/animator.cc#L194
AwaitVSync:https://sourcegraph.com/github.com/flutter/engine@master/-/blob/shell/common/animator.cc#L221
BeginFrame:https://sourcegraph.com/github.com/flutter/engine@master/-/blob/shell/common/animator.cc#L234
Signal() https://sourcegraph.com/github.com/flutter/engine@master/-/blob/shell/common/animator.cc#L109
dispatch_semaphore_signal https://sourcegraph.com/github.com/flutter/engine@master/-/blob/fml/synchronization/semaphore.cc#L42

Dispatch Semaphore是持有计数的信号,该信号是多线程编程中的计数类型信号。信号类似于过马路时的手旗,可以通过时举起手旗,不可通过时放下手旗。而在Dispatch Semaphore中使用了计数来实现该功能。计数为0时等待,计数为1或者大于1时放行。
信号量的使用比较简单,主要就三个API:createwaitsignal

使用篇

dispatch_semaphore_create可以生成信号量,参数value是信号量计数的初始值;dispatch_semaphore_wait会让信号量值减一,当信号量值为0时会等待(直到超时),否则正常执行;
dispatch_semaphore_signal会让信号量值加一,如果有通过dispatch_semaphore_wait函数等待Dispatch Semaphore的计数值增加的线程,会由系统唤醒最先等待的线程执行。
https://xiaozhuanlan.com/topic/4365017982

https://sourcegraph.com/github.com/flutter/engine@master/-/blob/runtime/runtime_controller.cc#L226:25

  1. bool RuntimeController::BeginFrame(fml::TimePoint frame_time) {
  2. if (auto* window = GetWindowIfAvailable()) {
  3. window->BeginFrame(frame_time);
  4. return true;
  5. }
  6. return false;
  7. }

https://sourcegraph.com/github.com/flutter/engine/-/blob/lib/ui/window/window.cc#L326

  1. void Window::BeginFrame(fml::TimePoint frameTime) {
  2. std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
  3. if (!dart_state)
  4. return;
  5. tonic::DartState::Scope scope(dart_state);
  6. int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds();
  7. tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame",
  8. {
  9. Dart_NewInteger(microseconds),
  10. }));
  11. UIDartState::Current()->FlushMicrotasksNow();
  12. tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {}));
  13. }

https://sourcegraph.com/github.com/flutter/engine/-/blob/lib/ui/hooks.dart#L175:12

pragma: https://github.com/dart-lang/sdk/blob/master/runtime/docs/pragmas.md @pragma('vm:entry-point')注解,其核心逻辑在于Tree-Shaking。在AOT(ahead of time)编译下,如果不能被应用主入口(main)最终可能调到,那么将被视为无用代码而丢弃。AOP代码因为其注入逻辑的无侵入性,显然是不会被main调到的,因此需要此注解告诉编译器不要丢弃这段逻辑

  1. @pragma('vm:entry-point')
  2. // ignore: unused_element
  3. void _beginFrame(int microseconds) {
  4. _invoke1<Duration>(window.onBeginFrame, window._onBeginFrameZone, Duration(microseconds: microseconds));
  5. }
  1. @pragma('vm:entry-point')
  2. // ignore: unused_element
  3. void _drawFrame() {
  4. _invoke(window.onDrawFrame, window._onDrawFrameZone);
  5. }
  1. mixin SchedulerBinding on BindingBase, ServicesBinding {
  2. void initInstances() {
  3. super.initInstances();
  4. _instance = this;
  5. window.onBeginFrame = _handleBeginFrame;
  6. window.onDrawFrame = _handleDrawFrame;
  7. }

handleBeginFrame
https://sourcegraph.com/github.com/flutter/flutter/-/blob/packages/flutter/lib/src/scheduler/binding.dart#L900:3

handleDrawFrame
https://sourcegraph.com/github.com/flutter/flutter/-/blob/packages/flutter/lib/src/scheduler/binding.dart#L951:8

FrameCallback:SchedulerBinding 类中有三个FrameCallback回调队列, 在一次绘制过程中,这三个回调队列会放在不同时机被执行:

  1. transientCallbacks:用于存放一些临时回调,一般存放动画回调。可以通过SchedulerBinding.instance.scheduleFrameCallback 添加回调。Triggered by the system’s [Window.onBeginFrame]
  2. persistentCallbacks:用于存放一些持久的回调,不能在此类回调中再请求新的绘制帧,持久回调一经注册则不能移除。SchedulerBinding.instance.addPersitentFrameCallback(),这个回调中处理了布局与绘制工作。Triggered by the system’s [Window.onDrawFrame]
  3. postFrameCallbacks:在Frame结束时只会被调用一次,调用后会被系统移除,可由 SchedulerBinding.instance.addPostFrameCallback() 注册,注意,不要在此类回调中再触发新的Frame,这可以会导致循环刷新。which are run after persistent callbacks, just /// before returning from the [Window.onDrawFrame] callback
  1. void handleDrawFrame() {
  2. try {
  3. // PERSISTENT FRAME CALLBACKS
  4. _schedulerPhase = SchedulerPhase.persistentCallbacks;
  5. for (FrameCallback callback in _persistentCallbacks)
  6. _invokeFrameCallback(callback, _currentFrameTimeStamp);
  7. // POST-FRAME CALLBACKS
  8. _schedulerPhase = SchedulerPhase.postFrameCallbacks;
  9. final List<FrameCallback> localPostFrameCallbacks =
  10. List<FrameCallback>.from(_postFrameCallbacks);
  11. _postFrameCallbacks.clear();
  12. for (FrameCallback callback in localPostFrameCallbacks)
  13. _invokeFrameCallback(callback, _currentFrameTimeStamp);
  14. } finally {
  15. }
  16. }

addPersistentFrameCallback
https://sourcegraph.com/github.com/flutter/flutter/-/blob/packages/flutter/lib/src/scheduler/binding.dart#L581

  1. final List<FrameCallback> _persistentCallbacks = <FrameCallback>[];
  2. void addPersistentFrameCallback(FrameCallback callback) {
  3. _persistentCallbacks.add(callback);
  4. }

RenderingBinding.drawFrame

https://sourcegraph.com/github.com/flutter/flutter/-/blob/packages/flutter/lib/src/rendering/binding.dart#L284

  1. mixin RendererBinding on BindingBase, SchedulerBinding, SemanticsBinding {
  2. @override
  3. void initInstances() {
  4. super.initInstances();
  5. addPersistentFrameCallback(_handlePersistentFrameCallback);
  6. }
  7. void _handlePersistentFrameCallback(Duration timeStamp) {
  8. drawFrame();
  9. }
  10. @protected
  11. void drawFrame() {
  12. assert(renderView != null);
  13. pipelineOwner.flushLayout(); // update dirty RenderObject layout
  14. pipelineOwner.flushCompositingBits();
  15. pipelineOwner.flushPaint();
  16. renderView.compositeFrame(); // call ui.window.render this sends the bits to the GPU
  17. pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
  18. }
  19. }

WidgetBinding.drawFrame (super.drawFrame RenderingBinding:drawFrame)
https://sourcegraph.com/github.com/flutter/flutter/-/blob/packages/flutter/lib/src/widgets/binding.dart

  1. @override
  2. void drawFrame() {
  3. buildOwner.buildScope(renderViewElement);
  4. super.drawFrame(); // RenderBinding.drawFrame()
  5. }
  • buildScope()
  • rebuild()
  • performRebuild()
  • drawFrame()
  • window.render()
  1. void buildScope(Element context, [ VoidCallback callback ]) {
  2. int dirtyCount = _dirtyElements.length;
  3. int index = 0;
  4. while (index < dirtyCount) {
  5. _dirtyElements[index].rebuild();
  6. index += 1;
  7. }
  8. Timeline.finishSync();
  9. }
  • Flutter 框架会按执行一系列动作: 动画(Animate)、构建(Build)、布局(Layout)和 绘制(Paint),最终生成一个场景(Scene)之后送往底层,由GPU绘制到屏幕上.

https://juejin.im/post/5c876a58f265da2db3058e2f

vsync

vsync(垂直同步)指计算机操作系统的一个信号功能。Android系统每隔 16ms 发出VSYNC信号,触发GPU对UI进行渲染。如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候由于还没有准备好,就无法进行更新任何内容,那么用户在32ms内看到的会是同一帧画面(卡顿现象),即丢帧现象。https://www.jianshu.com/p/0ee4b0124e56