Android系统UI从绘制到显示至屏幕一般为如图过程:先从相应的图片解码获得位图数据放到内存。然后使用图形引擎将位图数据按一定方式,渲染到可用于显示的图形内存上。最后系统SurfaceFlinger汇集所有图层的信息,采用离线合成或在线合成的方式,将图形内存的内容最后投射到屏幕显示出来。而本文就其中所用到的渲染方式作下简单介绍。
软件渲染
Android程序中图形绘制单元为一个Surface。每个Surface都有一个Canvas对象,它封装了由Skia提供的2D UI绘制接口,用来完成View在Surface上的绘制操作。每个Surface上的绘制内容就存储在DequeueBuffer一个Graphic Buffer中。每当窗口绘制时,通过函数lockCanvas获得一个Canvas,然后从顶层View开始,按树递归调用View的draw方法,在draw方法中,所有View中的onDraw实现被调用,以完成整个View的绘制,最后调用函数unlockAndPost将数据送至QueueBuffer一个Graphic Buffer中,以便SurfaceFlinger可以对Graphic Buffer的内容进行合成后显示到屏幕上去。
软件渲染流程中,Android并不会计算哪些View需要重绘,不只绘制了dirty的View,而是让所有View执行onDraw方法,这样效率不高,一定程度上影响了程序相应速度。而硬件渲染,通过GPU对软件图形图像的处理来减轻CPU的负担,从而使图像能够以更快的速度被处理,以达到程序提速的目的。
硬件渲染
硬件渲染即通过GPU,对厂商按照Open GL的规范实现的驱动间接调用来进行渲染。硬件渲染和软件渲染主要流程一样,在开始渲染之前,先获得一个Graphic Buffer但是这个Graphic Buffer会被封装成一个ANativeWindow。如同可以将Surface看作是Skia图形渲染库与操作系统底层图形系统的一个桥梁,同样可以将它看做是Open GL与底层图形系统建立的一个连接。然后将这个ANativeWindow传递给Open GL进行硬件加速渲染环境初始化。之后就可以调用Open GL的API进行UI绘制了,并将绘制出来内容就保存在前面获得的Graphic Buffer中。当绘制完毕,Android应用程序再调用libegl库提供的eglSwapBuffer接口将绘制好的UI显示到屏幕中。
其中与软件渲染不同的是,硬件渲染并不是立即执行绘制命令,它只是将对应的绘制命令以及参数保存在一个Display List中,接下来再通过Display List Renderer执行这个Display List的命令。使用Display List的目的是,先把视图的各种绘制函数翻译成绘制指令保存起来,对于没有发生改变的视图把原先保存的操作指令重新读取出来重放一次就可以了,提高了视图的显示速度,而对于需要重绘的View,则更新显示列表,然后再调用Open GL完成绘制。
虽然有了GPU的介入,分担了CPU的工作,同时有了Display List优化了图形渲染处理的流程,但是布局和事件响应还是全部集中在主线程,有时还是比较容易造成阻塞,于是又有了非主线程渲染。
非主线程渲染
在UI的主线程中更新画面很容易造成主线程的堵塞,造成程序的长时间无响应, 于是便有了SurfaceView。
SurfaceView是View的一个特殊子类,它拥有专有的Surface,即请求Window Manager创建一个新窗口,并改变窗口之间的深度信息来显示。如果SurfaceView的Window显示在主窗口的后面,SurfaceView将主窗口相应的位置设置成透明来使可见。其中的SurfaceHolder,可以把它当成surface的控制器,用来操纵surface,处理它的Canvas上画的效果和动画,控制表面,大小,像素等。
总结
为了总体提高系统显示性能,Android系统也是不断的对渲染性能这块进行改进。
在Android 1.5中,GLSurfaceView作为SurfaceView的补充,加入了EGL的管理,并自带了渲染线程。此前要在SurfaceView中要用GPU渲染,只好自已建上下文,而如今只要在回调中调用Open GL接口就可以了。
从Android 3.0开始支持启用Open GL硬件绘制加速。同时引入了SurfaceTexture,它是一个Texture, 也就是纹理, 可以用来捕获一个图像流的一帧来作为OpenGL 的纹理。这个图片流主要是来自相机的预览或视频的解码 。
之后Android 4.0中又增加一个TextureView控件,跳过Display List中间层,支持直接以Open GL纹理的形式来绘制UI,从而提高效率。同时它不会创建独立的window,它与常规的View一样,弥补了SurfaceView在进行普通View的旋转、缩放等变化时,其内容并不跟着一起变化的缺陷。
Android 4.3 增加了对Open GL ES 3.0 的支持,这个版本增加了对多缓冲区对象的支持;着色语言支持 32 位整数和浮点数据类型以及操作;增加了对多个纹理与多重目标渲染的支持。这些新特新大幅提高了移动平台的渲染性能。
到了Android 5.0,更是增加了一个专门负责UI渲染UIRender Thread,用来分担Android Main Thread的工作,在此之前,Android的Main Thread不仅负责渲染UI,还负责处理用户输入,而通过引进Render Thread来处理渲染工作, Main Thread可以更高专注高效地处理用户输入,这样使得在提高UI绘制效率的同时,也使得UI具有有更高的响应性。
Android 6.0后又提供了一个lockHardwareCanvas方法,用此方法可以直接得到硬件加速的Canvas。
在Android7.0之前,Surfaceview的显示也不受View的属性控制,所以不能进行平移,缩放等变换,要实现上述功能,要借助于TextureView。而到了Android 7.0时,它对SurfaceView自身和它的内容改变做了同步处理,比如通过SurfaceView实现视频播放时,对视频进行缩放变换SurfaceView会同步变化。
Android 应用图像展示的流畅性直接影响着用户体验,而本文从软件渲染,硬件渲染,非主线程渲染三个方面,对其各自的特点和流程作了简单介绍,在以后需要优化渲染性能时,我们可以选择从其一方面或多方面结合入手,来满足自己的需求。
本文作者:钱康(点融黑帮),就职于点融大前端,android开发工程师。
本文转自:微信号 - 点融黑帮(DianrongMafia),作者:钱康,转载此文目的在于传递更多信息,版权归原作者所有。