Detailed explanation of various Bindings in Flutter

foreword

All operations in Flutter are scheduled in various Bindings, and it is the existence of these binders that completely decouples the dependencies of Widget, Element, and RenderObject on the Platform side. Reading this article requires a certain Flutter foundation, such as: The drawing process of Flutter, the communication principle between Flutter and Platform, and the respective responsibilities of the three Flutter trees

WidgetsFlutterBinding

WidgetsFlutterBinding is a singleton storage, which inherits GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding, and is responsible for the bonding between Widget and Engine

class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
  static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding.instance == null)
      WidgetsFlutterBinding();
    return WidgetsBinding.instance!;
  }
}

All Bindings are called for the upper Widget, Element, and RenderObject, as shown in the following figure:

Event Dispatch Binder — GestureBinding

GestureBinding is the event distribution management in Flutter. For details, please refer to Talking About Flutter's Core Mechanisms - Event Distribution

  1. Register the event listener of the Engine layer, onPointerDataPacket is a method of the Engine layer callback
  void initInstances() {
    super.initInstances();
    _instance = this;
    window.onPointerDataPacket = _handlePointerDataPacket;
  }
  1. Dispatch events to RenderObject dispatchEvent
  void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) {
 ...
    for (final HitTestEntry entry in hitTestResult.path) {
      try {
        entry.target.handleEvent(event.transformed(entry.transform), entry);
      } catch (exception, stack) {
      }
    }
  }
  1. Handle event method handleEvent, process all gesture recognizers registered in RenderObject, and compete
  @override // from HitTestTarget
  void handleEvent(PointerEvent event, HitTestEntry entry) {
    pointerRouter.route(event);
    if (event is PointerDownEvent) {
      gestureArena.close(event.pointer);
    } else if (event is PointerUpEvent) {
      gestureArena.sweep(event.pointer);
    } else if (event is PointerSignalEvent) {
      pointerSignalResolver.resolve(event);
    }
  }

Task Scheduler Binder — SchedulerBinding

SchedulerBinding is a task scheduler, which is responsible for processing the timing of scheduling various types of tasks, executing some tasks before UI construction / after UI construction, in addition to prioritizing tasks

  1. handleBeginFrame is to execute the callback registered inside scheduleFrameCallback
  void handleBeginFrame(Duration? rawTimeStamp) {
    Timeline.startSync('Frame', arguments: timelineArgumentsIndicatingLandmarkEvent);
    _firstRawTimeStampInEpoch ??= rawTimeStamp;
    _currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
    if (rawTimeStamp != null)
      _lastRawTimeStamp = rawTimeStamp;

    _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;
    }
  }
  1. handleDrawFrame is to execute the callback registered in addPersistentFrameCallback/addPostFrameCallback, and the callback built by the UI pipeline is also executed inside
  void handleDrawFrame() {
    assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
    Timeline.finishSync(); // end the "Animate" phase
    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;
      Timeline.finishSync(); // end the Frame
      assert(() {
        if (debugPrintEndFrameBanner)
          debugPrint('▀' * _debugBanner!.length);
        _debugBanner = null;
        return true;
      }());
      _currentFrameTimeStamp = null;
    }
  }
  1. GPU rasterization time-consuming callback – addTimingsCallback, which can be used for GPU time-consuming detection
  void addTimingsCallback(TimingsCallback callback) {
    _timingsCallbacks.add(callback);
    if (_timingsCallbacks.length == 1) {
      assert(window.onReportTimings == null);
      window.onReportTimings = _executeTimingsCallbacks;
    }
    assert(window.onReportTimings == _executeTimingsCallbacks);
  }
  1. Priority execution of asynchronous tasks – scheduleTask
  Future<T> scheduleTask<T>(TaskCallback<T> task,Priority priority, {String? debugLabel, Flow? flow,}) {
    final bool isFirstTask = _taskQueue.isEmpty;
    final _TaskEntry<T> entry = _TaskEntry<T>(task, priority.value, debugLabel, flow,);
    _taskQueue.add(entry);
    if (isFirstTask && !locked)
      _ensureEventLoopCallback();
    return entry.completer.future;
  }
  1. The task before the next frame builds the task - scheduleFrameCallback, called in handleBeginFrame (refer to 1), for example: data value update in animation (ps: can be canceled by cancelFrameCallbackWithId method)
  int scheduleFrameCallback(FrameCallback callback, { bool rescheduling = false }) {
    scheduleFrame();
    _nextFrameCallbackId += 1;
    _transientCallbacks[_nextFrameCallbackId] = _FrameCallbackEntry(callback, rescheduling: rescheduling);
    return _nextFrameCallbackId;
  }
  1. The permanent callback task addPersistentFrameCallback, the task of drawFrame is registered in this method. ps: The callback is registered and it will be executed every time before the next frame
  void addPersistentFrameCallback(FrameCallback callback) {
    _persistentCallbacks.add(callback);
  }
  1. addPostFrameCallback will only be called once after addPersistentFrameCallback, in handleDrawFrame
  void addPostFrameCallback(FrameCallback callback) {
    _postFrameCallbacks.add(callback);
  }
  1. scheduleFrame() notifies the Engine that there is a UI update that needs to be called back
  void scheduleFrame() {
    if (_hasScheduledFrame || !framesEnabled)
      return;
    ensureFrameCallbacksRegistered();
    window.scheduleFrame();
    _hasScheduledFrame = true;
  }

Service Binder — ServicesBinding

ServicesBinding registration manages some platform services, such as messaging messenger _defaultBinaryMessenger, various life cycles of the platform, etc.

  void initInstances() {
    super.initInstances();
    _instance = this;
    //与platform通信的信使
    _defaultBinaryMessenger = createBinaryMessenger();
    //状态恢复回调
    _restorationManager = createRestorationManager();
    window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
    initLicenses();
    //系统消息处理,如内存低 。。
    SystemChannels.system.setMessageHandler((dynamic message) => handleSystemMessage(message as Object));
    //生命周期
    SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
    readInitialLifecycleStateFromNativeWindow();
  }
  1. _defaultBinaryMessenger is responsible for communicating with the platform. For details, please refer to the principle of MethodChannel/EventChannel in Flutter. The two new methods are as follows:
//发送二进制消息发给platform
  Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
    final Completer<ByteData?> completer = Completer<ByteData?>();
    ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
      try {
        completer.complete(reply);
      } catch (exception, stack) {
    });
    return completer.future;
  }

//处理platform发过来的二进制消息
  @override
  Future<void> handlePlatformMessage(
    String channel,
    ByteData? data,
    ui.PlatformMessageResponseCallback? callback,
  ) async {
    ByteData? response;
    try {
      final MessageHandler? handler = _handlers[channel];
      if (handler != null) {
        response = await handler(data);
      } else {
        ui.channelBuffers.push(channel, data, callback!);
        callback = null;
      }
    } 
  }
  1. handleSystemMessage handles system messages such as font change, out of memory
  //该方法被子类重写了
  @protected
  @mustCallSuper
  Future<void> handleSystemMessage(Object systemMessage) async {
    final Map<String, dynamic> message = systemMessage as Map<String, dynamic>;
    final String type = message['type'] as String;
    switch (type) {
      case 'memoryPressure':
        handleMemoryPressure();
        break;
    }
    return;
  }
  1. _parseAppLifecycleMessage life state callback processing
  static AppLifecycleState? _parseAppLifecycleMessage(String message) {
    switch (message) {
      case 'AppLifecycleState.paused':
        return AppLifecycleState.paused;
      case 'AppLifecycleState.resumed':
        return AppLifecycleState.resumed;
      case 'AppLifecycleState.inactive':
        return AppLifecycleState.inactive;
      case 'AppLifecycleState.detached':
        return AppLifecycleState.detached;
    }
    return null;
  }
  1. RestorationManager data save/restore management
@protected
RestorationManager createRestorationManager() {
  return RestorationManager();
}

Image Binder — PaintingBinding

PaintingBinding is relatively simple, it manages the Flutter image cache, creates image codecs, and warms up GPU shader programs

Auxiliary Service Binder — SemanticsBinding

SemanticsBinding handles auxiliary service events on Platform

Rendering Binders — RendererBinding

RendererBinding is a core component, which manages the rendering pipeline PipelineOwner (manages RenderObject), and registers platform display-related monitoring, such as: brightness change, font scaling factor change, etc. It creates the first RenderObject ---- RenderView

  1. initInstances initialization
  void initInstances() {
    super.initInstances();
    _instance = this;
    //渲染管线,管理需要刷新的RenderObject
    _pipelineOwner = PipelineOwner(
      onNeedVisualUpdate: ensureVisualUpdate,
      onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
      onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
    );
    window
      ..onMetricsChanged = handleMetricsChanged
      ..onTextScaleFactorChanged = handleTextScaleFactorChanged
      ..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
      ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
      ..onSemanticsAction = _handleSemanticsAction;
      //创建第一个 RenderObject  ---- RenderView
    initRenderView();
    _handleSemanticsEnabledChanged();
    assert(renderView != null);
    //注册绘制流水线回调,可参考SchedulerBinding中第6条
    addPersistentFrameCallback(_handlePersistentFrameCallback);
    initMouseTracker();
    if (kIsWeb) {
      addPostFrameCallback(_handleWebFirstFrame);
    }
  }

Drawing core method drawFrame

  @protected
  void drawFrame() {
    assert(renderView != null);
    //刷新需要布局
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    //刷新绘制
    pipelineOwner.flushPaint();
    if (sendFramesToEngine) {
    	//生成Scene发送到Engine
      renderView.compositeFrame(); // this sends the bits to the GPU
      pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
      _firstFrameSent = true;
    }
  }

Widget binder — WidgetsBinding

WidgetsBinding is the entrance of the three Widget trees, and handles some business between Widget and Element, such as: registering the monitoring of the life cycle for the Widget layer, brightness changes, etc.

  1. runApp Widget entry method
void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
    ..scheduleAttachRootWidget(app)
    ..scheduleWarmUpFrame();
}
  1. initInstances initialization
  void initInstances() {
    super.initInstances();
    _instance = this;
		//管理Element标脏,回收
    _buildOwner = BuildOwner();
    buildOwner!.onBuildScheduled = _handleBuildScheduled;
    //语言,时区
    window.onLocaleChanged = handleLocaleChanged;
    window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
    SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
    FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator);
  }
  1. drawFrame core method
  void drawFrame() {
		...
    try {
      if (renderViewElement != null)
        // 对标脏的Element进行重建,从而生成新的三棵树
        buildOwner!.buildScope(renderViewElement!);
        
        //见RendererBinding#drawFrame
      super.drawFrame();
      //卸载不再使用的Element
      buildOwner!.finalizeTree();
    } finally {
    }

   
  }

Summarize

Through the above analysis, we can know that the collaborative work between the Binding components in Flutter builds the Flutter UI interaction system, and they are relatively independent and only responsible for one type of responsibilities, which decouples the coupling between businesses.

Guess you like

Origin blog.csdn.net/jdsjlzx/article/details/123545142