likes
comments
collection
share

Flutter中UI更新和渲染流程

作者站长头像
站长
· 阅读数 13

我正在参加「掘金·启航计划」

Flutter的UI系统

说说UI系统

  • UI系统:基于一个平台,在此平台上实现GUI的一个系统,这里平台特指操作系统,如Android、iOS或者Windows、macOS
  • 各平台UI系统的原理是相通的,无论是Android还是iOS,将用户界面展示到屏幕的流程是相似的

Flutter UI系统

  • 无论Android SDK还是iOS的UIKit 的职责都是相同的,只是语言载体和底层的系统不同而已。
  • Flutter提供一套Dart API,在底层通过OpenGL这种跨平台的绘制库(内部会调用操作系统API)实现了一套代码跨多端。由于Dart API是调用操作系统API,因此性能接近原生。
  • Flutter UI系统和操作系统交互的这一部分原理,简单概括就是:组合和响应式。

Android的更新渲染

  • Android 原生开发中 View 更新渲染的起点是什么?—— VSync 信号
    • View 的属性发生变化时,以 requestLayout 为例,内部会将自身标记为 dirty,逐级调用 parent 的 requestLayout,最后来到顶层的 ViewRoot 会向系统注册一个 vsync 信号,当下一个 VSync 来临时会调用 ViewRootImpl 的 performMeasure、performLayout、performDraw,完成 view 的重绘。

Flutter中更新流程

  • Flutter 中更新流程类似,关注 Build、Layout 和 Paint 过程。UI 更新触发的条件是调用 State 对象的 setState 方法

setState链路分析

  • 看一下源码

      @protected
      void setState(VoidCallback fn) {
        //执行 VoidCallback 回调函数
        final dynamic result = fn() as dynamic;
        //省略各种断言函数代码,这个后期在分析断言抛出的各种异常场景
        _element.markNeedsBuild();
      }
    
    • 执行传入的回调函数,写在回调函数内的代码是执行在绘制之前的,会做一些数据的改变。
  • markNeedsBuild 代码

      void markNeedsBuild() {
        if (!_active)
          return;
        if (dirty)
          return;
        _dirty = true;
        owner.scheduleBuildFor(this);
      }
    
    • 调用 Element 的 markNeedsBuild 方法,内部 将自身标记,然后调用 BuildOwner 对象的 scheduleBuildFor 方法。
  • scheduleBuildFor 代码

      bool _inDirtyList = false;
    
      void scheduleBuildFor(Element element) {
        if (element._inDirtyList) {
          _dirtyElementsNeedsResorting = true;
          return;
        }
        if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
          _scheduledFlushDirtyElements = true;
          onBuildScheduled();
        }
        _dirtyElements.add(element);
        element._inDirtyList = true;
      }
    
    • BuildOwner 是 Widget 的管理类,内部记录了当前的标记 Element 元素集合。_inDirtyList 是一个布尔值,作用主要是避免多次调用 scheduleBuildFor 记录脏数据。
  • 整个流程梳理

    • 开发者 ----> 调用 setState 方法刷新UI
    • State 类 ----> 调用 void setState(VoidCallback fn) 方法 ----> 调用 _element.markNeedsBuild()
    • StatefulElement 类 ----> 调用 markNeedsBuild() 方法 ----> 调用 owner.scheduleBuildFor(this)
    • BuildOwner 类 ----> 调用 scheduleBuildFor(this) 方法 ----> 调用 onBuildScheduled() 方法,并且将element添加到_dirtyElements脏数据集合中
    • 根据 onBuildScheduled 回调callback定位到 ----> WidgetsBinding 类 initInstances() ,在这里初始化赋值 onBuildScheduled
    • WidgetsBinding 类 ----> 接着看 handleBuildScheduled ----> ensureVisualUpdate 方法 ----> 最终调用到 ensureFrameCallbacksRegistered 方法