1、没有硬件加速的UI绘制过程:在Android应用程序进程这一侧,每一个窗口都关联有一个Surface。每当窗口需要绘制UI时,就会调用其关联的Surface的成员函数lock获得一个Canvas,其本质上是向SurfaceFlinger服务Dequeue一个Graphic Buffer。Canvas封装了由Skia提供的2D UI绘制接口,并且都是在前面获得的Graphic Buffer上面进行绘制的。绘制完成之后,Android应用程序进程再调用前面获得的Canvas的成员函数unlockAndPost请求显示在屏幕中,其本质上是向SurfaceFlinger服务Queue一个Graphic Buffer,以便SurfaceFlinger服务可以对Graphic Buffer的内容进行合成,以及显示到屏幕上去。
2、有硬件加速的UI绘制过程:硬件加速渲染和软件渲染一样,在开始渲染之前,都是要先向SurfaceFlinger服务Dequeue一个Graphic Buffer。不过对硬件加速渲染来说,这个Graphic Buffer会被封装成一个ANativeWindow,并且传递给Open GL进行硬件加速渲染环境初始化。在Android系统中,ANativeWindow和Surface可以是认为等价的,只不过是ANativeWindow常用于Native层中,而Surface常用于Java层中。另外,我们还可以将ANativeWindow和Surface看作是像Skia和Open GL这样图形渲染库与操作系统底层的图形系统建立连接的一个桥梁。
Open GL获得了一个ANativeWindow,并且进行了硬件加速渲染环境初始化工作之后,Android应用程序就可以调用Open GL提供的API进行UI绘制了,绘制出来内容就保存在前面获得的Graphic Buffer中。当绘制完毕,Android应用程序再调用libegl库提供的一个eglSwapBuffer接口请求将绘制好的UI显示到屏幕中,其本质上与软件渲染过程是一样的,都是向SurfaceFlinger服务Queue一个Graphic Buffer,以便SurfaceFlinger服务可以对Graphic Buffer的内容进行合成,以及显示到屏幕上去。
3、绘制提速办法:在Android应用程序窗口中,每一个View都抽象为一个Render Node,而且如果一个View设置有Background,这个Background也被抽象为一个Render Node。这是由于在OpenGLRenderer库中,并没有View的概念,所有的一切可绘制的元素都抽象为一个Render Node。
每一个Render Node都关联有一个Display List Renderer。这里又涉及到另外一个概念——Display List。注意,这个Display List不是Open GL里面的Display List,不过它们在概念上是差不多的。Display List是一个绘制命令缓冲区。也就是说,当View的成员函数onDraw被调用时,我们调用通过参数传递进来的Canvas的drawXXX成员函数绘制图形时,我们实际上只是将对应的绘制命令以及参数保存在一个Display List中。接下来再通过Display List Renderer执行这个Display List的命令,这个过程称为Display List Replay。
引进Display List的概念有什么好处呢?主要是两个好处。第一个好处是在下一帧绘制中,如果一个View的内容不需要更新,那么就不用重建它的Display List,也就是不需要调用它的onDraw成员函数。第二个好处是在下一帧中,如果一个View仅仅是一些简单的属性发生变化,例如位置和Alpha值发生变化,那么也无需要重建它的Display List,只需要在上一次建立的Display List中修改一下对应的属性就可以了,这也意味着不需要调用它的onDraw成员函数。这两个好处使用在绘制应用程序窗口的一帧时,省去很多应用程序代码的执行,也就是大大地节省了CPU的执行时间。
4、线程:在Android 5.0之前,Android应用程序的Main Thread不仅负责渲染UI,还负责处理用户输入。通过引进Render Thread,我们就可以将UI渲染工作从Main Thread释放出来,交由Render Thread来处理,从而也使得Main Thread可以更专注高效地处理用户输入,这样使得在提高UI绘制效率的同时,也使得UI具有更高的响应性。
5、OPENGL 绘制环境初始化:Open GL环境也称为Open GL渲染上下文。一个Open GL渲染上下文只能与一个线程关联。在一个Open GL渲染上下文创建的Open GL对象一般来说只能在关联的Open GL线程中操作。这样就可以避免发生多线程并发访问发生的冲突问题。这与大多数的UI架构限制UI操作只能发生在UI线程的原理是差不多的。Render Thread有一个Task Queue,Main Thread通过一个代理对象Render Proxy向这个Task Queue发送一个drawFrame命令,从而驱使Render Thread执行一次渲染操作。因此,Android应用程序UI硬件加速渲染环境的初始化过程任务之一就是要创建一个Render Thread。 一个Android应用程序可能存在多个Activity组件。在Android系统中,每一个Activity组件都是一个独立渲染的窗口。由于一个Android应用程序只有一个Render Thread,因此当Main Thread向Render Thread发出渲染命令时,Render Thread要知道当前要渲染的窗口是什么。从这个角度看,Android应用程序UI硬件加速渲染环境的初始化过程任务之二就是要告诉Render Thread当前要渲染的窗口是什么。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)