确定一个应用当前是否使能了硬件加速有时候是非常有用的,特别对于一个自定义的View而言。如果你的应用有许多的自定义的绘制并且并不是所有的操作都被渲染管线正确绘制的时候,这些信息特别有用。
有两个方法来确定应用是否硬件加速:
1、如果一个View绑定了一个使能硬件加速的windowView.isHardwareAccelerated()将会返回true.
2、Canvas.isHardwareAccelerated()返回true如果Canvas使能了硬件加速。
你必须在你的绘制代码中做这些检查,并且尽量使用 Canvas.isHardwareAccelerated()而不是View.isHardwareAccelerated()。当一个View和一个使能了硬件加速的window绑定了的时候,他仍然可以使用一个非硬件加速的Canvas.例如,当把一个View绘制到一个bitmap来做缓存时。
Android Drawing Models
当硬件加速使能的时候,Android框架使用一个新的绘制模型,这个模型使用显示列表来把你的应用渲染到屏幕上。先理解Android不使用硬件加速时是怎样绘制图像的对理解Android使用显示列表以及它如何影响你的应用程序是有用的。如下的段落讲述了软件绘制模型以及使用硬件加速的绘制模型
Software-based drawing mode
在软件绘制模型中,View按照如下两步进行绘制:
1、刷新图像层
2、绘制图像层。
无论何时,当一个应用需要更新UI中的一部分时,它在内容改变的view上调用invalidate()(或者它的变体函数)函数。这个刷新消息会被传递到View层次,然后View会计算屏幕中需要重绘的区域(脏区域)。Android系统会绘制视图层次中所有和这个脏区域相交的区域。不好的是,这个模型有两个缺点:
1、首先,这个模型在每次绘制操作的时候都需要执行大量的代码。例如,如果你的应用中有一个按钮,这个按钮在另外一个View上面,如果你在按钮上面调用invalidate,即使按钮下面的View没有变化Android系统也会重绘他.
2、第二个问题就是这个绘制模型在你的应用中隐含着bug。由于Android系统会重绘所有跟脏区域有交集的区域,一个View的内容如果改变了,但是即使他没调用invalidate()方法,他也会被重绘。这个时候,你的这个View的状态依赖于另一个正在被绘制的View。但是这个会随着你每次改变应用程序而改变。由于这个,你应该在你自定义的View中当你修改了数据或者状态的时候,这些会修改会影响View的绘制的时候,要调用invalidate();
注意:Android 的View将会自动调用invalidate()方法当他们的属性改变的时候,例如背景或者一个TextView中的text
Hardware accelerated drawing model
Android仍然使用invalidate()和draw()来请求屏幕刷新已经渲染Views,但是他处理实际的绘制不一样。Android不是立即的去执行绘制命令,而是把他们这些绘制命令保存在显示列表中,显示 列表中包含了视图层次的绘制代码。另一个优化就是Android系统只需要记录和更新那些View通过invalidate()函数标记为脏的显示列表。没有更新的View可以简单的通过重新使用前面记录的显示列表来重绘。这个新的绘制模型包含三个阶段:
1、更新视图层次
2、记录和更新显示列表
3、绘制 显示列表
通过这个模型,你不能指望一个View和脏区域的相交的地方用他自己的draw方法来绘制。要确保把一个View的显示列表记录到了Android系统,你必须调用invalidate()方法。如果你忘记了调用这个方法,可能会造成一个View即使改变了,但是他看起来还是一样的,当然,这个bug发生的时候也很容易发现。
使用显示列表对动画性能也是有好处的,因为你设置指定的属性,如alpha或者rotation,不需要刷新目标View(他会自动调用)。这些优化也被应用到拥有显示列表的View(任何view当你的应用使能了硬件加速的时候)。例如,假如这里有一个LinearLayout,他包含一个ListView,这个ListView在一个Buttong上,这个LinearLayout的显示列表看起来可能是这样的:
DrawDisplayList(ListView)
DrawDisplayList(Button)
现在假设你想改变ListView的透明度,当你在ListView上调用完setAlpha(0.5f),显示列表可能包含如下:
SaveLayerAlpha(0.5)
DrawDisplayList(ListView)
Restore
DrawDisplayList(Button)
ListView复杂的绘制代码不会执行,而是代替的更新更简单的LinearLayout的显示列表。在一个硬件加速没有使能的应用中,list和他父控件的绘制代码都会被执行。