2.Android 4.0的绘制模型
当开启了硬件加速,Android框架将会使用一种新的绘制模型,这种模型将会使用显示列表把你的应用显示到屏幕上。要完全理解显示列表和他们如何影响你的应用程序,理解Android 4.0如何在非硬件加速的情况下如何绘制Views是很有必要的,下面将分别介绍软件加速和硬件加速。
2.1基于软件的绘制模型
在基于软件绘制模型中,View的绘制遵循以下两步:1.使整个控件层级无效。2.对层级进行绘制。
当一个应用程序需要更新它UI的一部分时,它将会调用内容发生改变的View的invalidate()方法(或者invalidate的变体)。Invalidate的消息按照View的层级关系向上传递用以计算需要重画的部分(即脏区域)。然后Android系统会对和脏区域有交集的所有View进行绘制,不幸的是这种模型中有两个缺点:
2.1.1 在这种模型中当在不同的层进行画的时候,会额外执行很多代码。例如一个Button是位于另外一个View之上,当对Button调用 Invalidate()时,Android就会对这个View进行重绘,即便这个View没有发生任何变化。
2.1.2 第二个问题是这种绘制模型会隐藏你Application中的Bug。因为Android系统会对和脏区域有交集的View进行重绘,在这种情况下如果一个view的内容发生了改变,即便这个View的Invalidate()的方法并没有得到调用,它也可能被重绘。你便会依赖调用了invalidate()的其他的控件以便获得正确的行为,因此每当你的Application发生改变时,这种行为多要随之发生改变。也是基于次因,在你的自定义控件中你必须不断地调用invalidate()方法,当你的数据或者是状态会影响View的绘制代码时。
注意:Android的View当它们的属性发生改变时会自动的调用Invalidate()。比如,你改变一个 Textview的背景或者是它的文本。
2.2 基于硬件加速模型
Android 系统仍然通过invalidate()和draw()去请求屏幕更新和重新渲染,但是实际处理画的方式是不同的。不是立即执行画的命令,Android而会将所有画的命令记录在一个显示列表里面,这个显示列表包含了输出的View层级的绘制代码。还有一个优化就是Android在显示列表中只会记录和更新显示层级中通过调用invalidate()函数被标记为“脏”的view。没有被请求刷新的view可以通过重新请求先前的显示列表以便重画。新的绘制模型包括有三个步骤:1.禁用整个View层级。2.记录和更新显示列表。3.绘制显示列表。
使用这个模型你不能依赖一个View和脏区域有交集就会执行draw()方法。要确保Android系统记录了一个View的显示列表,你必须调用invalidate()方法,如果忘记了调用刷新,会使View即便是发生了改变后也会看起来相同,这是一个比较容易发现bug的方式。
使用显示列表的方式对动画的表现也是很有好处的,因为设置指定的属性值,比如透明度或者旋转,就不需要请求刷新目标View(这将自动执行)。这项优化也应用于有显示列表的Views(启用了硬件加速的View),例如,现在有一个LinearLayout包含了一个ListView和Button,listview在button的上面。这时候LinearLayout的显示列表如下所示:
◆DrawDisplayList(ListView) ;
◆DrawDisplayList(Button) ;
假设你现在你想更新这个Listview的不透明度,在设置Listview的 setAlpha(0.5f) 属性之后,LinearLayout的显示列表应该包含如下:
◆ SaveLayerAlpha(0.5)
◆ DrawDisplayList(ListView)
◆ Restore
◆ DrawDisplayList(Button)
这时候绘制Listview的复杂过程就会省略了,取而代之的是简单的更新了LinearLayout的显示列表。如果一个应用程序并没有启用硬件加速,Listview和它的父view的画的代码都会重新执行。