1.为什么会有Flutter出现
这要从移动端跨平台解决方案说起,目前大部分企业还是采用的
- 平台独立开发
- iOS开发工程师(OC,swift)在苹果商店发布应用
- Android(java ,kotlin) 在安卓的各大应用商店发布。对于公司来讲成本是非常高的
- WebView(基于JavaScript 和 webView)的跨平台解决方案
- 安卓和ios都有webView。可以直接渲染CSS和Html,都可以通过JS调用原生,但是他本身是不能调用一些本地服务的,要通过Js桥接。而且性能不理想,交互体验极差。所以直接就被pass了
- React Native
- 他在Flutter出现之前是无疑是最优秀的跨平台解决方案。FaceBook 在 2015年提供的开源的移动端应用开发框架
- RN使用JavaScript语言,类似于HTML的JSX,以及CSS来开发移 动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可 以进入移动应用开发领域。
- 并且在保留基本渲染能力的基础上,用原生自带的 UI 组件实现核 心的渲染引擎,从而保证了良好的渲染性能。
- 但是,由于RN的本质是通过JavaScript VM调用原生接口,通信 相对比较低效,而且框架本身不负责渲染,而是是间接通过原生 进行渲染的。
- Flutter
- Flutter利用Skia绘图引擎,直接通过CPU、GPU进行绘制,不需要依赖任何原生的控件
- Android操作系统中,我们编写的原生控件实际上也是依赖于Skia进行绘制,所以flutter在某些Android操作系统上甚至还要高 于原生(因为原生Android中的Skia必须随着操作系统进行更新,而Flutter SDK中总是保持最新的)
- 而类似于RN的框架,必须通过某些桥接的方式先转成原生进行调用,之后再进行渲染。
- 用一张图来说明一下渲染机制
2.Flutter的绘制原理
- 图像是如何显示的
- 无论是视频还是GIF图片,还是操作系统给我们看到的图形化界面中的画面,都是图像。
- 当图片连续播放的频率超过16帧(16张图片),人眼就会感觉非常流畅,当少于16帧时,会感觉到卡顿
- 所以我们平时看到的电影,通常都是24帧或者30帧的(李安之前拍摄120帧的电影,目的就是让图片间隔更小,画面更加的流畅)
- 帧率与刷新率
- 帧率(fps):Frames Per Second
- 刷新率:显示器的频率,比如iPhone的 60Hz/s、iPad Pro的 120Hz/s
- CPU/GPU 向 Buffer 中生成图像,屏幕从 Buffer 中取 图像、刷新后显示。这 是一个典型的生产者——消费者模型。理想的情况是帧率和刷新频率相等,每绘制一帧,屏幕显示一帧。但是实际往往它们的大小是不同的。
- 如果没有锁来控制同步,很容易出现问题。例如: 当帧率大于刷新频率,当屏幕还没有刷新第 n-1 帧的时候,GPU 已经在生成第 n 帧了, 从上往下开始覆盖第 n-1 帧的数据,当屏幕开始刷新第 n-1 帧的时候,Buffer 中的数据上半部分是第 n 帧数据, 而下半部分是第 n-1 帧的数据, 显示出来的图像就会出现上半部分和下半部分明显偏差 的现象,我们称之为 “tearing”(撕裂)
-
解决撕裂:双重缓存(double buffer)
image.png
- 为了解决单缓存的“tearing”问题,就出现了 双重缓存和 VSync ,
两个缓存区分别为 Back Buffer 和 Frame Buffer。
GPU 向 Back Buffer 中写数据,屏幕从 Frame Buffer 中读数据。
VSync 信号负责调度从 Back Buffer 到 Frame Buffer 的复制操作,当然底层不是通过复制,而是通过交换内存地址方式,所以可以瞬 间完成,效率是非常高的; - 工作流程
在某个时间点,一个屏幕刷新周期完成,VSync 信号产生,先完成复制操作,然 后通知 CPU/GPU 绘制下一帧图像。
复制操作完成后屏幕开始下一个刷新周期,即将刚复制到 Frame Buffer 的数据显示到屏幕上。
在这种模型下,只有当 VSync 信号产生时,CPU/GPU 才会开始绘 制。
- 双重缓存存在的问题
- 双重缓存的缺陷在于:当 CPU/GPU 绘制一帧的时间过长(比如超过 16ms)时,会产生 Jank(画面停顿,甚至空白)。
- 蓝色代表 CPU 生成 Display List;
- 绿色代表 GPU 执行 Display List 中的命令从而生成帧; p 黄色代表生成帧完成,在屏幕上显示;
图片说明: CPU生成蓝色B的数据,由GPU进行B的绘制,但是这个过长由于过长,那么第二个A就产生了Jank。 B在屏幕上显示之后,发出Vsync信号,A开始绘制,但是由于绘制时间 过长,第二个B位置又产生了Jank
- 随之而来的 三重缓存
如何解决双重缓存的问题了?
- 在第二个A展示,Vsync信号发出后,直接绘制C Buffer
- 在第一个B展示,Vsync信号发出后,绘制A Buffer
- 因为C已经在缓存中,可以直接从缓存中取出C Buff来进行展示,依次类 推
- 其实本质是在每次Vsync信号发出后,多缓存一个Buffer作为备用
-
Flutter的绘制原理
image.png
- GPU将信号同步到 UI 线程
- UI 线程用Dart来构建图层树
- 图层树在GPU 线程进行合成
- 合成后的视图数据提供给Skia 引擎
- Skia 引擎通过OpenGL 或者 Vulkan将显示内容提供给GPU
- 这也是flutter区别于React Native的本质区别:
- React Native 之类的框架,只是通过 JavaScript 虚拟机扩展调用系统组件,由 Android 和 iOS 系统进行组件的渲染; Flutter 是自己完成了组件渲染的闭环
- Flutter的渲染引擎 skia
Skia就是 Flutter向 GPU提供数据的途径。Skia(全称Skia Graphics Library(SGL))是一个由C++编写的开源图形库,能在低端设备如手机上呈现高质量的2D图形,最初由Skia公司开发,后被 Google收购,应用于Android、Google Chrome、Chrome OS等等当中。
- 目前,Skia 已然是 Android 官方的图像渲染引擎了,因此 Flutter Android SDK 无需内嵌 Skia 引擎就可以获得天然的 Skia 支持;
- 而对于 iOS 平台来说,由于 Skia 是跨平台的,因此它作为 Flutter iOS 渲染引 擎被嵌入到 Flutter 的 iOS SDK 中,替代了 iOS 闭源的 Core Graphics/Core Animation/Core Text,这也正是 Flutter iOS SDK 打包的 App 包体积比 Android 要大一些的原因。
- 底层渲染能力统一了,上层开发接口和功能体验也就随即统一了,开发者再也不 用操心平台相关的渲染特性了。也就是说,Skia 保证了同一套代码调用在 Android 和 iOS 平台上的渲染效果是完全一致的。
网友评论