Android Flutter 了解UI显示原理
一篇值得多看几遍的Flutter显示原理的文章(通俗易懂)
转自:https://book.flutterchina.club/chapter14/flutter_ui_system.html
UI系统原理
我们知道显示器(屏幕)是由一个个物理显示单元
组成,每一个单元我们可以称之为一个物理像素点
,而每一个像素点可以发出多种颜色
,显示器成相的原理就是在不同的物理像素点上显示不同的颜色,最终构成完整的图像
一个像素点能发出的所有颜色总数
是显示器的一个重要指标,比如我们所说的1600万色的屏幕就是指一个像素点可以显示出1600万种颜色
,而显示器颜色是有RGB三基色
组成,所以1600万即2的24次方,即每个基本色(R、G、B)深度扩展至8 bit(位),颜色深度越深,所能显示的色彩更加丰富靓丽
为了更新显示画面,显示器是以固定的频率刷新(从GPU取数据),比如有一部手机屏幕的刷新频率是 60Hz。当一帧图像绘制完毕后准备绘制下一帧时,显示器会发出一个垂直同步信号
(如VSync), 60Hz的屏幕就会一秒内发出 60次
这样的信号。而这个信号主要是用于同步CPU、GPU和显示器
的。一般地来说,计算机系统中,CPU、GPU和显示器以一种特定的方式协作:CPU将计算好的显示内容提交给 GPU
,GPU渲染后放入帧缓冲区
,然后视频控制器
按照同步信号从帧缓冲区取帧数据传递给显示器显示
CPU和GPU的任务是各有偏重的,CPU主要用于基本数学
和逻辑计算
,而GPU主要执行和图形处理相关
的复杂的数学,如矩阵变化
和几何计算
,GPU的主要作用就是确定最终输送给显示器的各个像素点的色值
操作系统绘制API的封装
由于最终的图形计算和绘制都是由相应的硬件来完成,而直接操作硬件的指令通常都会有操作系统屏蔽,应用开发者通常不会直接面对硬件,操作系统屏蔽了这些底层硬件操作
后会提供一些封装后的API
供操作系统之上
的应用调用,但是对于应用开发者来说,直接调用这些操作系统提供的API是比较复杂和低效
的,因为操作系统提供的API往往比较基础,直接调用需要了解API的很多细节。正是因为这个原因,几乎所有用于开发GUI程序
的编程语言都会在操作系统之上再封装一层
,将操作系统原生API封装在一个编程框架和模型中
,然后定义一种简单的开发规则
来开发GUI应用程序
,而这一层抽象,正是我们所说的“UI”系统,如Android SDK
正是封装了Android操作系统API,提供了一个“UI描述文件XML+Java操作DOM”的UI系统,而iOS的UIKit 对View的抽象也是一样的
,他们都将操作系统API抽象成一个基础对象(如用于2D图形绘制的Canvas),然后再定义一套规则来描述UI,如UI树结构,UI操作的单线程原则等
Flutter UI系统
我们可以看到,无论是Android SDK还是iOS的UIKit 的职责都是相同的,它们只是语言载体和底层的系统不同而已。那么可不可以实现这么一个UI系统:可以使用同一种编程语言开发
,然后针对不同操作系统API
抽象一个对上接口一致
,对下适配不同操作系统
的中间层,然后在打包编译时再使用相应的中间层代码?如果可以做到,那么我们就可以使用同一套代码编写跨平台的应用
了。而Flutter的原理正是如此,它提供了一套Dart
API,然后在底层通过OpenGL这种跨平台的绘制库
(内部会调用操作系统API)实现了一套代码跨多端。由于Dart API也是调用操作系统API,所以它的性能接近原生。
注意,虽然Dart是先调用了
OpenGL
,OpenGL才会调用操作系统API,但是这仍然是原生渲染
,因为OpenGL只是操作系统API的一个封装库
,它并不像WebView渲染那样需要JavaScript运行环境和CSS渲染器,所以不会有性能损失
至此,我们已经介绍了Flutter UI系统和操作系统交互的这一部分原理,现在需要说一些它对应用开发者定义的开发标准
。简单概括就是:组合和响应式
。我们要开发一个UI界面,需要通过组合其它Widget
来实现,Flutter中,一切都是Widget
,当UI要发生变化时,我们不去直接修改DOM,而是通过更新状态
,让Flutter UI系统来根据新的状态来重新构建UI