End

Flutter 陈航 04-关键技术 知识体系 架构

本文地址


目录

04 | Flutter 的关键技术是什么?

原文

Flutter 出现的历史背景

跨平台开发方式研发虽然效率高,但为了抹平多端平台差异,各类解决方案暴露的组件和 API 较原生开发相比少很多,因此研发体验和产品功能并不完美。

所以,最成功的跨平台开发方案其实是依托于浏览器控件的 Web。浏览器保证了 99% 的概率下 Web 的需求都是可以实现的,不需要业务将就“技术”。不过,Web 最大的问题在于它的性能和体验与原生开发存在肉眼可感知的差异,因此并不适用于对体验要求较高的场景。

对于用户体验更接近于原生的 React Native,对业务的支持能力却还不到浏览器的 5% ,仅适用于中低复杂度的低交互类页面。面对稍微复杂一点儿的交互和动画需求,开发者都需要 case by case 地去 review,甚至还可能要通过原生代码去扩展才能实现。

这些因素,也就导致了虽然跨平台开发从移动端诞生之初就已经被多次提及,但到现在也没有被很好地解决。

Flutter 是构建 Google 物联网操作系统 Fuchsia 的 SDK,主打跨平台、高保真、高性能。开发者可以通过 Dart 语言开发 App,一套代码可以同时运行在 iOS 和 Android 平台。 Flutter 使用 Native 引擎渲染视图,并提供了丰富的组件和接口,这无疑为开发者和用户都提供了良好的体验。

Flutter 是怎么运转的

与用于构建移动应用程序的其他大多数框架不同,Flutter 是重写了一整套包括底层渲染逻辑和上层开发语言的完整解决方案。这样不仅可以保证视图渲染在 Android 和 iOS 上的高度一致性(即高保真),在代码执行效率和渲染性能上也可以媲美原生 App 的体验(即高性能)。

这,就是 Flutter 和其他跨平台方案的本质区别:

  • React Native 之类的框架,只是通过 JavaScript 虚拟机扩展调用系统组件,由 Android 和 iOS 系统进行组件的渲染;
  • Flutter 则是自己完成了组件渲染的闭环。

那么,Flutter 是怎么完成组件渲染的呢?这需要从图像显示的基本原理说起。

在计算机系统中,图像的显示需要 CPU、GPU 和显示器一起配合完成:CPU 负责图像数据计算,GPU 负责图像数据渲染,而显示器则负责最终图像显示

CPU 把计算好的、需要显示的内容交给 GPU,由 GPU 完成渲染后放入帧缓冲区,随后视频控制器根据垂直同步信号(VSync)以每秒 60 次的速度,从帧缓冲区读取帧数据交由显示器完成图像显示。

操作系统在呈现图像时遵循了这种机制,而 Flutter 作为跨平台开发框架也采用了这种底层方案。

图 1 Flutter 绘制原理

可以看到,Flutter 关注如何尽可能快地在两个硬件时钟的 VSync 信号之间计算并合成视图数据,然后通过 Skia 交给 GPU 渲染:

  • UI 线程使用 Dart 来构建视图结构数据
  • GPU 线程对这些数据进行图层合成,随后交给 Skia 引擎加工成 GPU 数据
  • OpenGL 最终将这些数据提供给 GPU 进行渲染

构建 Flutter 的关键技术,即 Skia 和 Dart。

Skia 是什么

要想了解 Flutter,你必须先了解它的底层图像渲染引擎 Skia。

Skia 是一款用 C++ 开发的、性能彪悍的 2D 图像绘制引擎,其前身是一个向量绘图软件。2005 年被 Google 公司收购后,因为其出色的绘制表现被广泛应用在 ChromeAndroid 等核心产品上。Skia 在图形转换、文字渲染、位图渲染方面都表现卓越,并提供了开发者友好的 API。

因此,架构于 Skia 之上的 Flutter,也因此拥有了彻底的跨平台渲染能力。通过与 Skia 的深度定制及优化,Flutter 可以最大限度地抹平平台差异,提高渲染效率与性能。

底层渲染能力统一了,上层开发接口和功能体验也就随即统一了,开发者再也不用操心平台相关的渲染特性了。也就是说,Skia 保证了同一套代码调用在 Android 和 iOS 平台上的渲染效果是完全一致的。

为什么是 Dart

很多人说,选择 Dart 是 Flutter 推广的一大劣势,毕竟多学一门新语言就多一层障碍。想想 Java 对 Android,JavaScript 对 NodeJS 的推动,如果换个语言可能就不一样了。

但,Google 公司给出的原因很简单也很直接:Dart 语言开发组就在隔壁,对于 Flutter 需要的一些语言新特性,能够快速在语法层面落地实现;而如果选择了 JavaScript,就必须经过各种委员会和浏览器提供商漫长的决议。

当然,Google 公司选择使用 Dart 作为 Flutter 的开发语言,我想还有其他更有说服力的理由:

  • Dart 同时支持 JIT 和 AOT。在开发期使用 JIT,开发周期异常短,调试方便;发布期使用 AOT,本地代码的执行更高效,代码性能和用户体验也更卓越。
  • Dart 作为一门现代化语言,集百家之长,拥有其他优秀编程语言的诸多特性。
  • Dart 避免了抢占式调度和共享内存,可以在没有锁的情况下进行对象分配和垃圾回收,在性能方面表现相当不错。

Dart 是一门优秀的现代语言,最初设计也是为了取代 JavaScript 成为 Web 开发的官方语言。而随着 Flutter 的发布,Dart 开始转型,其自身定位也发生了变化,专注于改善构建客户端应用程序的体验。

Flutter 的原理

首先,我们来看一下 Flutter 的架构图。

Flutter 架构采用分层设计,从下到上分为三层,依次为:Embedder、Engine、Framework。

  • Embedder 是操作系统适配层,实现了渲染 Surface 设置(Render Surface Setup),线程设置(Thread Setup),以及平台插件(Native Plugins)等平台相关特性(Platform Specific)的适配。

  • Engine 层实现了 Flutter 的渲染引擎(Rendering)、文字排版(Text Layout)、事件处理(System Events)和 Dart 运行时(Dart VM)等功能。

    • Skia 和 Text 为上层接口提供了调用底层渲染和排版的能力
    • Dart 为 Flutter 提供了运行时调用 Dart 和渲染引擎的能力
    • Engine 层的作用是将它们组合起来,从它们生成的数据中实现视图渲染
  • Framework 层是一个用 Dart 实现的 UI SDK,包含了动画(Animation)、图形绘制(Painting)和手势识别(Gestures)等功能。Flutter 还基于这些基础能力,根据 Material 和 Cupertino 两种视觉设计风格封装了一套 UI 组件库。

接下来,我以界面渲染过程为例,和你介绍 Flutter 是如何工作的。

页面中的各界面元素(Widget)以树的形式组织,即控件树。Flutter 通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。而渲染对象树在 Flutter 的展示过程分为四个阶段:布局、绘制、合成、渲染

布局

Flutter 采用深度优先机制遍历渲染对象树,决定渲染对象树中各渲染对象在屏幕上的位置和尺寸。在布局过程中,渲染对象树中的每个渲染对象都会接收父对象的布局约束参数,决定自己的大小,然后父对象按照控件逻辑决定各个子对象的位置,完成布局过程。

为了防止因子节点发生变化而导致整个控件树重新布局,Flutter 加入了一个机制——布局边界(Relayout Boundary),可以在某些节点自动或手动地设置布局边界,当边界内的任何对象发生重新布局时,不会影响边界外的对象,反之亦然。

绘制

布局完成后,渲染对象树中的每个节点都有了明确的尺寸和位置。Flutter 会把所有的渲染对象绘制到不同的图层上。与布局过程一样,绘制过程也是深度优先遍历,而且总是先绘制自身,再绘制子节点。

为了解决这一问题,Flutter 提出了与布局边界对应的机制——重绘边界(Repaint Boundary)。在重绘边界内,Flutter 会强制切换新的图层,这样就可以避免边界内外的互相影响,避免无关内容置于同一图层引起不必要的重绘。

重绘边界的一个典型场景是 Scrollview。ScrollView 滚动的时候需要刷新视图内容,从而触发内容重绘。而当滚动内容重绘时,一般情况下其他内容是不需要重绘的,这时候重绘边界就派上用场了。

合成和渲染

终端设备的页面越来越复杂,因此 Flutter 的渲染树层级通常很多,直接交付给渲染引擎进行多图层渲染,可能会出现大量渲染内容的重复绘制,所以还需要先进行一次图层合成,即将所有的图层根据大小、层级、透明度等规则计算出最终的显示效果,将相同的图层归类合并,简化渲染树,提高渲染效率。

合并完成后,Flutter 会将几何图层数据交由 Skia 引擎加工成二维图像数据,最终交由 GPU 进行渲染,完成界面的展示。

学习 Flutter 需要掌握的知识

终端设备越来越碎片化,需要支持的操作系统越来越多,从研发效率和维护成本综合考虑,跨平台开发一定是未来大前端的趋势。而 Flutter 提供了一套彻底的移动跨平台方案,也确实弥补了如今跨平台开发框架的短板,解决了业界痛点,极有可能成为跨平台开发领域的终极解决方案。

我按照 App 的开发流程(开发、调试测试、发布与线上运维)将 Flutter 的技术栈进行了划分,里面几乎包含了 Flutter 开发需要的所有知识点。掌握了这些知识点后,你也就具备了企业级应用开发的必要技能。

2022-12-3

posted @ 2022-12-03 02:32  白乾涛  阅读(301)  评论(0编辑  收藏  举报