20讲UI优化(上):UI渲染的几个关键概念
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
20讲UI 优化(上):UI 渲染的⼏个关键概念
在开始今天的学习前,我祝各位同学新春快乐、⼯作顺利、身体健康、阖家幸福,绍⽂给您拜年啦!
多年来,有那么⼀群苦逼的Android 开发,他们饱受碎⽚化之苦,⾯对着各式各样的⼿机屏幕尺⼨和分辨率,还要与“凶残”的产品和UI 设计师过招,⽇复⼀⽇、年复⼀年的做着UI 适配和优化⼯作,蹉跎着⻘春的岁⽉。更加不幸的是,最近两年这个趋势似乎还愈演愈烈:刘海屏、全⾯屏,还有即将推出的柔性折叠屏,UI 适配将变得越来越复杂。
UI 优化究竟指的是什么呢?我认为所谓的UI 优化,应该包含两个⽅⾯:⼀个是效率的提升,我们可以⾮常⾼效地把UI 的设计图转化成应⽤界⾯,并且保证UI 界⾯在不同尺⼨和分辨率的⼿机上都是⼀致的;另⼀个是性能的提升,在正确实现复杂、炫酷的UI 设计的同时,需要保证⽤户有流畅的体验。
那如何将我们从⽆穷⽆尽的UI 适配中拯救出来呢?
UI 渲染的背景知识
究竟什么是UI 渲染呢?Android 的图形渲染框架⼗分复杂,不同版本的差异也⽐较⼤。但是⽆论怎么样,它们都是为了将我们代码中的View 或者元素显示到屏幕中。
⽽屏幕作为直接⾯对⽤户的⼿机硬件,类似厚度、⾊彩、功耗等都是⼚家⾮常关注的。从功能机⼩⼩的⿊⽩屏,到现在超⼤的全⾯屏,我们先来看⼿机屏幕的发展历程。
1. 屏幕与适配
作为消费者来说,通常会⽐较关注屏幕的尺⼨、分辨率以及厚度这些指标。Android 的碎⽚化问题令⼈痛⼼疾⾸,屏幕的差异正是碎⽚化问题的“中⼼”。屏幕的尺⼨从3英⼨到10英⼨,分辨率从320到1920应有尽有,对我们UI 适配造成很⼤困难。除此之外,材质也是屏幕⾄关重要的⼀个评判因素。⽬前智能⼿机主流的屏幕可分为两⼤类:⼀种是LCD (Liquid Crystal
每个做UI 的Android 开发,上辈⼦都是折翼的天使。
通过dp加上⾃适应布局可以基本解决屏幕碎⽚化的问题,也是Android推荐使⽤的屏幕兼容性适配⽅案。但是它会存在两个⽐较⼤的问题:
不⼀致性。因为dpi与实际ppi的差异性,导致在相同分辨率的⼿机上,控件的实际⼤⼩会有所不同。
效率。设计师的设计稿都是以px为单位的,开发⼈员为了UI适配,需要⼿动通过百分⽐估算出dp值。
除了直接dp适配之外,⽬前业界⽐较常⽤的UI适配⽅法主要有下⾯⼏种:
限制符适配⽅案。主要有宽⾼限定符与smallestWidth限定符适配⽅案,具体可以参考《Android ⽬前稳定⾼效的UI适配⽅案》《smallestWidth 限定符适配⽅案》。
今⽇头条适配⽅案。通过反射修正系统的density值,具体可以参考《⼀种极低成本的Android屏幕适配⽅式》《今⽇头条适配⽅案》。
除了屏幕,UI渲染还依赖两个核⼼的硬件:CPU与GPU。UI组件在绘制到屏幕之前,都需要经过Rasterization(栅格化)操作,⽽栅格化操作⼜是⼀个⾮常耗时的操作。GPU(Graphic Processing Unit )也就是图形处理器,它主要⽤于处理图形运算,可以帮助我们加快栅格化操作。
你可以从图上看到,软件绘制使⽤的是Skia库,它是⼀款能在低端设备如⼿机上呈现⾼质量的2D跨平台图形框架,类似Chrome、Flutter内部使⽤的都是Skia库。
3. OpenGL与Vulkan
对于硬件绘制,我们通过调⽤OpenGL ES接⼝利⽤GPU完成绘制。OpenGL是⼀个跨平台的图形API,它为2D/3D图形处理硬件指定了标准软件接⼝。⽽OpenGL ES是OpenGL的⼦集,专为嵌⼊式设备设计。
在官⽅硬件加速的⽂档中,可以看到很多API都有相应的Android API level限制。
不⽀持的API,我们需要使⽤软件绘制模式,渲染的性能将会⼤⼤降低。
Android 7.0把OpenGL ES升级到最新的3.2版本同时,还添加了对Vulkan的⽀持。Vulkan是⽤于⾼性能3D图形的低开销、跨平台 API。相⽐OpenGL ES,Vulkan在改善功耗、多核优化提升绘图调⽤上有着⾮常明显的优势。
在国内,“王者荣耀”是⽐较早适配Vulkan的游戏,虽然⽬前兼容性还有⼀些问题,但是Vulkan版本的王者荣耀在流畅性和帧数
稳定性都有⼤幅度提升,即使是战况最激烈的团战阶段,也能够稳定保持在55~60帧。
我曾经在⼀篇⽂章看过⼀个⽣动的⽐喻,如果把应⽤程序图形渲染过程当作⼀次绘画过程,那么绘画过程中Android的各个图形组件的作⽤是:
画笔:Skia或者OpenGL。我们可以⽤Skia画笔绘制2D图形,也可以⽤OpenGL来绘制2D/3D图形。正如前⾯所说,前者使⽤CPU绘制,后者使⽤GPU绘制。
画纸:Surface。所有的元素都在Surface这张画纸上进⾏绘制和渲染。在Android中,Window是View的容器,每个窗⼝都会关联⼀个Surface。⽽WindowManager则负责管理这些窗⼝,并且把它们的数据传递给SurfaceFlinger。
画板:Graphic Buffer。Graphic Buffer缓冲⽤于应⽤程序图形的绘制,在Android 4.1之前使⽤的是双缓冲机制;在Android
整个流程如上图所示:
Surface。每个View都由某⼀个窗⼝管理,⽽每⼀个窗⼝都关联有⼀个Surface。
Canvas。通过Surface的lock函数获得⼀个Canvas,Canvas可以简单理解为Skia底层接⼝的封装。
Graphic Buffer。SurfaceFlinger会帮我们托管⼀个BufferQueue,我们从BufferQueue中拿到Graphic Buffer,然后通过Canvas以及Skia将绘制内容栅格化到上⾯。
SurfaceFlinger。通过Swap Buffer把Front Graphic Buffer的内容交给SurfaceFinger,最后硬件合成器Hardware Composer 合成并输出到显示屏。
整个渲染流程是不是⾮常简单?但是正如我前⾯所说,CPU对于图形处理并不是那么⾼效,这个过程完全没有利⽤到GPU的⾼性能。
硬件加速绘制
所以从Androd 3.0开始,Android开始⽀持硬件加速,到Android 4.0时,默认开启硬件加速。