fanleiym 2012-04-15
当硬加速被启用,Android框架利用一个新的绘制模式来把你的应用呈现到屏幕,这个模式利用了一个显示列表.要完全理解显示列表以及它如何影响你的应用,先要理解android如何在非硬加速下绘制View.下面的小节描述了软加速的和硬加速的绘制models.
软件绘制模式
在软件绘制模式,view按以下两步进行绘制:
1使整个View层级都变得无效
2绘制所有的View层级
任何时候一个应用需要更新部分UI时,它应在任何改变了内容的View上调用invalidate()(或它的任一变体),使界面无效的消息在整个View层级中传播以计算应被绘制的屏幕区域(脏区域).之后Android系统绘任View层级中所有与脏区域有交集的View.不幸的是,这种绘制模式有两个缺点:
第一,这个模式需要在每个绘制路径中都执行很多代码.比如,如果你的应用在一个button上调用了invalidate()并且这个button位于另一个view之上,即使这个View没有变化,Android系统也会绘制这个View.
第二个问题是这个绘制模式可能隐藏你应用中的bug.因为Android系统会绘制与脏区域有交集的view们,那么一个你改变了内容的view可能在没有被调用invalidate()时也会被重绘了.当这种情况发生时,你只能依赖那个需要重绘的view来获得正确的行为.但这个行为可能在你每次修改你的应用时都会改变.因此,在任何你修改了数据或状态而影响到绘制代码的时候,你总是应该在你的自定义view上调用invalidate().
注:Androidview们会在它们的属性被改变时自动调用invalidate(),比如一个TextView的背景和文本改变时.
硬加速绘制模式
Android系统依然使用invalidate()和draw()来请求屏幕更新并画出views,但是对实际的绘制处理却不一样.现在不是在收到绘制命令立即执行了,而是Android系统把绘制命令记录到显示列表中,这个列表中包含了View层级的绘制代码的输出.另一个优化是Android系统只需为那些通过invalidate()标记为脏的View记录和更新显示列表.没有被invalidated的Views可以简单地使用先前的显示列表中的记录进行重绘.新的绘制模式包含三个阶段:
1使整个View层级都无效
2记录并更新显示列表
3画显示列表
使用此模式,你再不能依靠让View与脏区域交界而使它的draw()方法被调用.要保证Android系统记录下view的显示列表,你必须调用invalidate().忘记这样做会导致一个view总是一个模样,即使改变了它.但这是一个很容易被找出的bug.
使用显示列表还对提升动画性能有益,因为设置了某个属性,比如alpha或rotation等,不再需invalidating目标view(自动做了).这个优化也会应用到拥有显示列表的view上(当你的应用被硬加速时的任何view).例如,假设有一个LinearLayout包含了一个ListView和一个Button,ListView位于Button之上,LinearLayout的显示列表看起来如下:
DrawDisplayList(ListView)
DrawDisplayList(Button)
假设现在你想改变ListView的opacity,在调用了ListView的setAlpha(0.5f)后,显示列表现在包含如下项:
SaveLayerAlpha(0.5)
DrawDisplayList(ListView)
Restore
DrawDisplayList(Button)
ListView复杂的绘制过程没有被执行,而是仅更新了更简单的LinearLayout的显示列表.如果在一个未硬加速的应用中,列表和它爹的绘制代码都会被重新执行.
不支持的绘制操作
当启用了硬加速,2D呈现管道会支持通用的Canvas绘制操作,也支持不常用的操作.所有的绘制操作被用来呈现widgets,layouts以及通用高级视觉效果,比如反光和平铺纹理.下面的列表描述了已知的不能被硬加速支持的绘制操作:
Canvas clipPath() clipRegion() drawPicture() drawPosText() drawTextOnPath() drawVertices() Paint setLinearText() setMaskFilter() setRasterizer()
另外,还有一些操作的行为在启用硬加速后会变得不一样:
Canvas clipRect():异或,差异和反差异剪切都被忽略.3D变换不应用到剪切框中 drawBitmapMesh():颜色数组被忽略 drawLines():反锯齿不被支持 setDrawFilter():可以设置,但被忽略 Paint setDither():被忽略 setFilterBitmap():滤镜一直启用 setShadowLayer():仅对文本起作用 ComposeShader ComposeShader只能包含不同类型的着色器(比如一个BitmapShader和一个LinearGradient,不能是两个BitmapShader) ComposeShader不能包含ComposeShader
如果你的应用被这些缺少的特性或限制影响了,你可以通过调用setLayerType(View.LAYER_TYPE_SOFTWARE,null)为受影响的部分关闭硬加速.用此方法,你依然可以在其它地方享用到硬加速.