前言

Flutter中所有的运转都是在各种Binding中调度的,也正是这些绑定器的存在彻底解耦了Widget 、 Element 、RenderObject 对 Platform端的依赖,阅读此文需要有一定的Flutter基础,如:Flutter的绘制流程,Flutter与Platform通信原理,Flutter 三棵树各自的职责

WidgetsFlutterBinding

WidgetsFlutterBinding是一个单例存,它继承了GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding,负责Widget和Engine之间的粘合工作

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

所有的Binding都是为上层的Widget,Element,RenderObject提供调用的,如下图所示:

事件调度绑定器 — GestureBinding

GestureBinding是对Flutter中的事件分发管理,具体可以参考浅谈Flutter核心机制之— 事件分发

  1. 注册Engine 层的事件监听 ,onPointerDataPacket是Engine层回调的一个方法
  void initInstances() {super.initInstances();_instance = this;window.onPointerDataPacket = _handlePointerDataPacket;}
  1. 分发事件到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. 处理事件方法handleEvent, 处理所有RenderObject中注册的手势识别器,进行竞技
  @override // from HitTestTargetvoid 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);}}

任务调度绑定器 — SchedulerBinding

SchedulerBinding是任务调度器,它负责处理对各种类型任务调度的时机, 执行 UI构建前/UI构建后的一些任务,除此之外还可以对任务进行优先级排序

  1. handleBeginFrame是执行里面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 CALLBACKSTimeline.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是执行addPersistentFrameCallback/addPostFrameCallback中注册的回调,UI流水线构建的回调也在里面执行
  void handleDrawFrame() {assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);Timeline.finishSync(); // end the "Animate" phasetry {// 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 Frameassert(() {if (debugPrintEndFrameBanner)debugPrint('▀' * _debugBanner!.length);_debugBanner = null;return true;}());_currentFrameTimeStamp = null;}}
  1. GPU光栅化耗时回调 – addTimingsCallback,可以用来做GPU耗时检测
  void addTimingsCallback(TimingsCallback callback) {_timingsCallbacks.add(callback);if (_timingsCallbacks.length == 1) {assert(window.onReportTimings == null);window.onReportTimings = _executeTimingsCallbacks;}assert(window.onReportTimings == _executeTimingsCallbacks);}
  1. 优先级执行异步任务 – 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. 在下一帧构建任务前的任务 – scheduleFrameCallback,在handleBeginFrame中调用(参考1),例如: 动画中的数据值更新 (ps:能够被cancelFrameCallbackWithId方法取消)
  int scheduleFrameCallback(FrameCallback callback, { bool rescheduling = false }) {scheduleFrame();_nextFrameCallbackId += 1;_transientCallbacks[_nextFrameCallbackId] = _FrameCallbackEntry(callback, rescheduling: rescheduling);return _nextFrameCallbackId;}
  1. 永久回调任务addPersistentFrameCallback,drawFrame的任务就是注册在此方法中。ps:注册了该回调每次下一帧之前都会执行一次
  void addPersistentFrameCallback(FrameCallback callback) {_persistentCallbacks.add(callback);}
  1. addPostFrameCallback在addPersistentFrameCallback之后,只会被调用一次,在handleDrawFrame中调用
  void addPostFrameCallback(FrameCallback callback) {_postFrameCallbacks.add(callback);}
  1. scheduleFrame()通知Engine有UI更新需要被回调
  void scheduleFrame() {if (_hasScheduledFrame || !framesEnabled)return;ensureFrameCallbacksRegistered();window.scheduleFrame();_hasScheduledFrame = true;}

服务绑定器 — ServicesBinding

ServicesBinding注册管理了一些平台服务,如消息通信信使_defaultBinaryMessenger,平台的各种生命周期等等

  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是负责与platform通信,详情可参考Flutter中MethodChannel/EventChannel的原理,两个和新方法如下:
//发送二进制消息发给platformFuture<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发过来的二进制消息@overrideFuture<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处理系统消息,如字体改变、内存不足
  //该方法被子类重写了@protected@mustCallSuperFuture<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生命状态回调的处理
  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 数据保存/恢复管理
@protected
RestorationManager createRestorationManager() {return RestorationManager();
}

图像绑定器 — PaintingBinding

PaintingBinding比较简单,就是管理了Flutter图像缓存和创建图像编解码器,以及对GPU着色器程序预热

辅助服务绑定器 — SemanticsBinding

SemanticsBinding处理Platform上辅助服务事件

渲染绑定器 — RendererBinding

RendererBinding是一个核心组件,它里面管理了渲染管线PipelineOwner(管理RenderObject),以及注册platform显示相关的监听,如:亮度改变,字体缩放因子改变等等,它里面创建了第一个RenderObject ---- RenderView

  1. initInstances 初始化
  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  ---- RenderViewinitRenderView();_handleSemanticsEnabledChanged();assert(renderView != null);//注册绘制流水线回调,可参考SchedulerBinding中第6条addPersistentFrameCallback(_handlePersistentFrameCallback);initMouseTracker();if (kIsWeb) {addPostFrameCallback(_handleWebFirstFrame);}}

绘制核心方法 drawFrame

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

Widget绑定器 — WidgetsBinding

WidgetsBinding是Widget三棵树的入口,处理Widget, Element之间的一些业务,如:给Widget层注册生命周期的监听,亮度改变等等

  1. runApp Widget入口方法
void runApp(Widget app) {WidgetsFlutterBinding.ensureInitialized()..scheduleAttachRootWidget(app)..scheduleWarmUpFrame();
}
  1. initInstances 初始化化
  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 核心方法
  void drawFrame() {...try {if (renderViewElement != null)// 对标脏的Element进行重建,从而生成新的三棵树buildOwner!.buildScope(renderViewElement!);//见RendererBinding#drawFramesuper.drawFrame();//卸载不再使用的ElementbuildOwner!.finalizeTree();} finally {}}

总结

通过以上分析可以得知Flutter中各Binding组件之间的协同工作构建出Flutter UI交互系统,它们之间又相对独立的只负责一类职责这样很好的解耦了业务之间的耦合度

详解Flutter中各种Binding相关推荐

  1. 详解OpenCV中的Lucas Kanade稀疏光流单应追踪器

    详解OpenCV中的Lucas Kanade稀疏光流单应追踪器 1. 效果图 2. 源码 参考 这篇博客将详细介绍OpenCV中的Lucas Kanade稀疏光流单应追踪器. 光流是由物体或相机的运动 ...

  2. python操作目录_详解python中的文件与目录操作

    详解python中的文件与目录操作 一 获得当前路径 1.代码1 >>>import os >>>print('Current directory is ',os. ...

  3. python3中unicode怎么写_详解python3中ascii与Unicode使用

    这篇文章主要为大家详解python3中ascii与Unicode使用的相关资料,需要的朋友可以参考下# Auther: Aaron Fan ''' ASCII:不支持中文,1个英文占1个字节 Unic ...

  4. foreach php,详解PHP中foreach的用法和实例

    本篇文章介绍了详解PHP中foreach的用法和实例,详细介绍了foreach的用法,感兴趣的小伙伴们可以参考一下. 在PHP中经常会用到foreach的使用,而要用到foreach,就必须用到数组. ...

  5. python open 打开是什么类型的文件-详解Python中open()函数指定文件打开方式的用法...

    文件打开方式 当我们用open()函数去打开文件的时候,有好几种打开的模式. 'r'->只读 'w'->只写,文件已存在则清空,不存在则创建. 'a'->追加,写到文件末尾 'b'- ...

  6. python中list[1啥意思_详解Python中list[::-1]的几种用法

    本文主要介绍了Python中list[::-1]的几种用法,分享给大家,具体如下: s = "abcde" list的[]中有三个参数,用冒号分割 list[param1:para ...

  7. java 死锁 内存消耗_详解Java中synchronized关键字的死锁和内存占用问题

    先看一段synchronized 的详解: synchronized 是 java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并 ...

  8. pythonnamedtuple定义类型_详解Python中namedtuple的使用

    namedtuple是Python中存储数据类型,比较常见的数据类型还有有list和tuple数据类型.相比于list,tuple中的元素不可修改,在映射中可以当键使用. namedtuple: na ...

  9. python停止线程池_详解python中Threadpool线程池任务终止示例代码

    需求 加入我们需要处理一串个位数(0~9),奇数时需要循环打印它:偶数则等待对应时长并完成所有任务:0则是错误,但不需要终止任务,可以自定义一些处理. 关键点 定义func函数处理需求 callbac ...

最新文章

  1. 堪称神级的 Java 技术栈手册火了!
  2. python接口测试-认识GET请求
  3. docker dockerfile 映射端口范围 批量映射端口
  4. 操作系统01_进程和线程管理
  5. python语言程序设计实践教程答案实验六_20192417 实验一《Python程序设计》实验报告...
  6. 你知道WPF这三大模板实例运用吗?
  7. 【转】ABP源码分析四:Configuration
  8. python调用函数怎么表示_Python---7函数(调用定义函数)
  9. $python日期和时间的处理
  10. 带你重新认识ZooKeeper!java数组合并去重
  11. SQL SERVER-Extendevent检测TempDB增长
  12. LeetCode Student Attendance Record I
  13. y电容如何选型_到底什么是安规电容?有什么作用?一文彻底请明白
  14. 安装bt5到u盘方法与步骤
  15. WINDOWS 2008 R2 下安装usb转serial线缆驱动
  16. 【乌拉圭】乌拉圭决定采用日本-巴西数字电视制式标准
  17. 运维审计是什么意思?有什么作用?用什么软件好?
  18. 微信小程序支付V3(Java版)
  19. 服务器声卡如何虚拟,服务器没声卡远程桌面连接怎么实现听到服务器的声音
  20. 手把手写深度学习(16):用CILP预训练模型搭建图文检索系统/以图搜图/关键词检索系统

热门文章

  1. Opencv——图像的矩
  2. NAS折腾系列二:番外篇之瘦客户机+DoraOS实现远程办公
  3. 快速拿下CKA认证考试,这些要求和tips你得知道
  4. shp系列(七)——利用C++进行Shx文件的写(创建)
  5. 辉芒微IO单片机FT60F211-RB
  6. 135编辑器如何插入文件
  7. Python——列表的方法
  8. 筛选excel表格C++实现
  9. 干货全拿走-用Excel制作小市值轮动价值投资选股器
  10. echart旭日图_echarts之用饼图制作带labelline的旭日图(一)