第1个回答 2017-09-14
安卓有2种绘制模型:
一.软件绘制模型,这里由CPU主导绘图,视图按照以下2个步骤绘图。
让视图结构(view hierarchy)失效。
绘制整个视图结构。
当应用程序需要更新它的部分UI时,都会调用内容发生改变的View对象的invalidate()方法。无效(invalidation)消息请求会在View对象层次结构中传递,以便计算出需要重绘的屏幕区域(脏区)。然后,Android系统会在View层次结构中绘制所有的跟脏区相交的区域。但是,这种方法有两个缺点:
1. 绘制了不需要重绘的视图(与脏区域相交的区域)
2. 掩盖了一些应用的bug(由于会重绘与脏区域相交的区域)
注意:在View对象的属性发生变化时,如背景色或TextView对象中的文本等,Android系统会自动的调用该View对象的invalidate()方法。
二.硬件加速绘制模型,这里由GPU主导绘图,视图按照以下3个步骤绘图。
让视图结构失效。
记录和更新显示列表(Display List)。
绘制显示列表。
这种模式下,Android系统依然会使用invalidate()方法和draw()方法来请求屏幕更新和展现View对象。但Android系统并不是立即执行绘制命令,而是首先把这些View的绘制函数作为绘制指令记录一个显示列表中,然后再读取显示列表中的绘制指令调用OpenGL相关函数完成实际绘制。另一个优化是,Android系统只需要针对由invalidate()方法调用所标记的View对象的脏区进行记录和更新显示列表。没有失效的View对象就简单重用先前显示列表记录的绘制指令来进行简单的重绘工作。
使用显示列表的目的是,把视图的各种绘制函数翻译成绘制指令保存起来,对于没有发生改变的视图把原先保存的操作指令重新读取出来重放一次就可以了,提高了视图的显示速度。而对于需要重绘的View,则更新显示列表,然后再调用OpenGL完成绘制。
在这种绘制模型下,我们不能依赖一个视图与脏区(dirty region)相交而导致它的draw()方法被自动调用,所以必须要手动调用该视图的invalidate()方法去更新显示列表。如果忘记这么做可能导致视图在改变后不会发生变化。