Android 图形的渲染 - MrWu94/AndroidNote GitHub Wiki

1、 图形的渲染可分为两种:软件渲染和硬件渲染。软件渲染是靠CPU计算各种坐标并绘制,主要是占用内存;硬件渲染是靠GPU,主要占用显存,一般的3D图形程序(OpenGL、DirectX)都是GPU加速的。

在Android3.0之前,2D绘图API只支持软件渲染模式,从Android3.0开始,2D绘图API开始支持GPU硬件渲染,即View中的Canvas的绘图操作会使用GPU,所以从Android 3.0(API Level 11)开始,View中就多了一些和硬件相关的方法。如果App的AndroidManifest.xml文件中定义的 targetSdkVersion大于或等于14(android 4.0),那么Android会默认为App启用GPU渲染2D图形,我们也可以自己决定是否使用GPU,见下文。如果开启了GPU硬件加速,那么Android会用OpengGL绘图中常见的Display List技术对OpenGL ES中的绘图命令进行缓存,提高绘图效率与速度

Application

在AndroidMenifest.xml的中添加如下的属性即可在整个App的所有Activity的View中启用GPU硬件加速渲染2D图形:

<application android:hardwareAccelerated="true" >

Activity

你既可以在Application级别上控制GPU是否启用,也可以在Activity级别对其就进行控制。比如你的App中有多个Activity,你想让大部分Activity启用GPU硬件加速,但有一个Activity你不想启用硬件加速,你可以通过以下的配置实现:

<application android:hardwareAccelerated="true">
    <activity ... />
    <activity android:hardwareAccelerated="false" />
</application>

Window

如果你想要更加细粒度地对GPU的使用进行控制,你可以通过代码对指定的Window启用GPU硬件加速,如下代码所示:

getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

需要注意的是在运行时不能通过代码禁用掉某个Window的硬件加速。

基于软件的绘制模式

在软件绘制模式,view是按照下面两个步骤进行绘制的:

1、无效化View层次结构

2、绘制View的层次结构

当应用需要更新它的一部分UI,它会调用view的invalidate方法,无效化消息就会通过各种途径传递到View的层次结构,然后计算屏幕中需要重绘的区域(脏区域),android系统还会对View层次结构中脏区域相交的所有view进行绘制,对于这种绘制模式,有两个不好的地方:

第一、这个模式在每一次绘制都需要执行大量的代码,比如,如果你的应用对一个button调用invalidate,而这个button坐标在其他view的上方,那么android系统就会重绘这些view,即使他们没有发生改变,仅仅因为它们处于和button相交的区域

第二、绘制模式会有一些隐藏bug,当android系统重绘那些相交的views的时候,即使你没有调用invalidate,相交区域内的一个被改变过的view可能也会进行重绘,这个时候,你通过其他的view的绘制来给这个view进行重绘,当你不经意间修改你的代码,这个时候可能你已经忘了这一段代码有这个隐藏的bug,修改代码后你发现显示的效果有问题,本该进行重绘的区域没有重绘,你就会怀疑是自己的代码逻辑出现问题了,所以应该尽可能在修改view的数据或状态的时候,对每一个你修改过的自定义View,主动调用他们的invalidate方法。

PS:当view的属性发生改变的时候,例如TextView上的background color或者text,这个时候android view会自动调用invalidate,进行重绘

硬件加速绘制模式

android系统依然使用invalidate和draw函数来请求屏幕刷新渲染界面,但实际上绘制的时候是有区别的,不同于立即执行绘制命令,android系统会先把它们记录在display list上,这个display lists包含view的层次结构的绘制代码。其他的优化是android系统只需要记录和更新display lists,通过调用invalidate函数来标记那些脏view,那些没有被标记为invalidate的view可以简单的进行重绘通过事先记录在display list上的记录。新的绘制模式包含三个步骤:

1、无效化View的层次结构

2、记录和更新显示列表

3、绘制显示列表

使用这个模式,你不能再依赖脏区域内相交的view来绘制其他的view,为了确保android系统记录这个view的display list,你必须调用invalidate,不调用的话,就会导致一个view看起来跟之前是一样的,即使你已经改变它了。所以这就一次性解决了两个问题,对于View层次结构中不想重绘的View,只要不调用那个View的invalidae即可。

使用display list对动画效果也有好处,因为设置指定的属性,例如alpha或者rotation,不需要调用目标view的invalidate,因为它会自动完成,这个优化也应用到view的display list。例如,假设有一个LinearLayout在Button上面有一个ListView,那么对于LinearLayout的display list就会像这样的:

DrawDisplayList(ListView)

DrawDisplayList(Button)

假设现在你通过调用setAlpha(0.5)来修改ListView的透明度,那么display list就变成这样了:

SaveLayerAlpha(0.5)

DrawDisplayList(ListView)

Restore

DrawDisplayList(Button)

关于ListView的复杂的绘制代码并没有被执行,系统只是更新了LinearLayout的display list,如果应用没有启用硬件加速,那么listview以及它的父容器LinearLayout的绘制代码都会再次执行。

参考:http://blog.csdn.net/iispring/article/details/49835061