原文地址:
http://developer.android.com/guide/topics/graphics/hardware-accel.html
硬件加速
Android 3.0 (API level 11), 开始支持
所有的View 的canvas都会使用GPU,但是硬件的加速会占有一定的RAM。
在API >= 14上,默认是开启的,如果你的应用只是标准的View和Drawable,全局都打开硬件加速,是不会有任何问题的。
然而,硬件加速并不支持所有的2D画图的操作,这时开着它,可能会影响到你的自定义控件或者绘画,出现异常等行为,
所以android对于硬件加速提供了可选性
如果你的应用执行了自定义的绘画,可以通过在真机上测试开启硬件加速查找问题
硬件加速的级别
Application <application android:hardwareAccelerated="true" ...>
Activity
Window
View
Note: 你可以关闭View级别的硬件加速,但是你不能在View级别开启硬件加速,因为它还依赖其他的设置
两种获取是否支持硬件加速的方式
View.isHardwareAccelerated() returns true if the View is attached to a hardware accelerated window.
Canvas.isHardwareAccelerated() returns true if the Canvas is hardware accelerated
如果必须进行这样的验证,建议你在draw的代码块中使用:Canvas.isHardwareAccelerated(),因为如果一个View被attach到一个硬件加速的Window上,
即使没有硬件加速的Canvas,它也是可以被绘制的。比如:将一个View以bitmap的形式进行缓存
Android的绘制模型
开启硬件加速后,Android框架将采用新的绘制模型。
基于软件的绘制模型和基于硬件的绘制模型的区别:
应用程序调用invalidate()更新UI的某一部分,失效(invalidation)消息将会在整个视图层中传递,计算每个需要重绘的区域(即脏区域)。
然后Android系统将会重绘所有和脏区域有交集的view。很明显,这种绘图模式存在缺点:
1. 每个绘制操作中会执行不必要的代码。比如如果应用程序调用invalidate()重绘button,而button又位于另一个view之上,
即使该view没有变化,也会进行重绘。
2. 可能会掩盖一些应用程序的bug。因为android系统会重绘与脏区域有交集的view,所以view的内容可能会在没有调用invalidate()的情况
下重绘。这可能会导致一个view只有在其它view时失效才得到正确的行为。这种行为可能在每次修改应用的时候都会发生改变。
因此,你需要一直调用invalidate在你的自定义控件上,不管那些涉及到重绘的代码是否修改了数据或状态。
Note:android view 在属性值变化的时候会自动调用invalidate,比如一个TextView的颜色或者背景的变化。
Android系统仍然使用invalidate()和draw()来绘制view,但在处理绘制上有所不同。
Android系统记录绘制命令到显示列表,包含的视图层次的绘图输出,而不是立即执行绘制命令。
另一个优化就是Android系统只需记录和更新标记为脏(通过invalidate())的view。新的绘制模型包含三个步骤:
1. Invalidate the hierarchy
2. 记录和更新显示列表
3. 绘制显示列表
在这种模式下,你不能指望一个视图相交的肮脏的地区会执行其draw()方法。为了确保Android系统记录视图的显示列表,你必须调用
invalidate()。否则会导致View不会刷新。
使用显示列表对动画的性能也会有好处,因为某些明确的属性,例如 alpha或者旋转,不要求invalidate目标View,(会自发的执行)。
这种优化也可以应用于所有显示列表的视图(当application硬件加速的时候)。
假设有一个LinearLayout,包含上述按钮列表。对于LinearLayout显示列表看起来像这样:
假设你想改变ListView的透明度,在listview上调用了setAlpha之后,这个显示列表包括:
ListView的复杂的draw代码块没有执行,相反,系统只会更新这个更简化的显示列表,如果应用中没有开启硬件加速,list和其父类的draw代码块
会再次执行。
硬件加速的2D渲染管道的建立是第一个支持不成比例的绘画,但是过高的值会影响到绘图操作的质量。
这些绘制的操作是按照1.0的规模纹理实现的,由GPU转化。在API级别<17,伴随着规模的增长会导致
如果你的应用程序是由任何这些特征缺失或限制的影响,你可以通过setLayerType(View.LAYER_TYPE_SOFTWARE, null).关闭它,不会影响到你再
别的地方使用硬件加速。
在所有版本的Android,所有的View具有渲染到锁屏缓冲区的能力,或通过View的绘制缓存,或者调用 Canvas.saveLayer().
锁屏缓冲区或者layers拥有几种用途。在实现复杂的动画或者应用于组件效果器的时候。比如, 实现退色效果:通过Canvas.saveLayer 临时的分发一个view到layer,
然后以一个不透明的参数返回.
在Android 3(API级别11开始),你有更多的控制如何以及何时使用层与视图setlayertype()方法。
这个API有两个参数:Layer的类型和一个可选的Paint,你可以使用Paint参数应用到颜色过滤器,特殊的混合模式,或者对于一个图层的不透明度。
视图可以使用三个layer类型:
LAYER_TYPE_NONE:
正常的使用,不会通过锁屏的缓冲区返回。
LAYER_TYPE_HARDWARE:
视图是由硬件实现为硬件机构如果应用硬件加速。如果应用程序没有硬件加速,这层型表现相同layer_type_software。
LAYER_TYPE_SOFTWARE:
layer的类型依赖于你的需求;
性能:
使用硬件层类型来渲染一个视图到纹理层,一旦视图被渲染成一层,其绘图代码不必执行,直到视图调用invalidate()执行。
一些动画,如α-动画,然后可以被直接应用到层,使用GPU来做是非常高效的。
视觉效应:
使用硬件或软件层型和涂料适用于特殊的视觉处理的观点。例如,你可以通过colormatrixcolorfilter画一个黑白相间的视图。
兼容性:
使用一个软件层类型去强制渲染一个视图。如果一个被硬件加速的视图(例如,如果你的整个应用程序的硬件加速),就会出现
渲染的问题,这是一个解决硬件渲染管线限制的简单的方法。
当你的应用程序的硬件加速,硬件层可以提供更快和更平滑的动画。
在每秒60帧运行一个处理大量绘图操作的复杂动画有时候是不可能的。
这可以通过使用硬件层渲染为硬件纹理缓解。然后硬件纹理可以用来制作视图的动画,不需要视图在动画的时候不断重绘自己。视图不被重绘,
除非你改变视图的属性,调用了invalidate(),或者你手动的调用invalidate,你将不会得到一个平滑的动画。这时你需要考虑开启硬件层应用
到你的动画。
当一个视图是由硬件层的支持,它的一些属性通过layer被合成到屏幕的方式处理。
设置这些属性将是有效的因为他们不需要视图invalidate和重绘。下面列出的属性影响layer合成的方式
alpha:
Changes the layer's opacity
x, y, translationX, translationY:
Changes the layer's position
scaleX, scaleY:
Changes the layer's size
rotation, rotationX, rotationY:
Changes the layer's orientation in 3D space
pivotX, pivotY:
Changes the layer's transformations origin
因为硬件层使用视频内存,它是高度推荐你在启动动画的时候开启它们,在动画完成的时候关闭它们。
Tip & Tricks
切换硬件加速的2D图形可以立即提高性能,但你仍应该遵循以下建议以便有效地利用GPU应用程序
减少应用程序中的View的数量
需要绘制的视图越多,它的速度就越慢。这同样适用于软件渲染。减少视图是一个简单的方法来优化您的UI。
避免透支
不在彼此的顶部画太多的层次。移除任何被它上面不透明的视图完全遮盖的视图。如果你需要绘制几层的混合在一起,把它们合并为一个单一的层。
对于当前的硬件,一个好的经验法则是不在屏幕上画出每帧的像素数超过2.5次(在一个位图透明像素计数!)。
不要创建渲染对象的绘制方法
一个常见的错误是,每一次渲染方法被调用的时候都创建一个新的Paint或一个新的Path。这迫使垃圾收集器运行更加频繁,也绕过缓存优化的硬件管道。
不要太频繁的修改形状
复杂的形状,Path,Circle,每次都是通过texture masks来渲染的,每次创建或者修改Path,这个硬件管道会创建一个新的mask,而这时十分昂贵的。
不要太频繁的修改Bitmap
每次改变Bitmap的内容,都会作为一个GPU texture再次上传,然后下次重新绘制。
谨慎使用alpha
硬件加速
Android 3.0 (API level 11), 开始支持
所有的View 的canvas都会使用GPU,但是硬件的加速会占有一定的RAM。
在API >= 14上,默认是开启的,如果你的应用只是标准的View和Drawable,全局都打开硬件加速,是不会有任何问题的。
然而,硬件加速并不支持所有的2D画图的操作,这时开着它,可能会影响到你的自定义控件或者绘画,出现异常等行为,
所以android对于硬件加速提供了可选性
如果你的应用执行了自定义的绘画,可以通过在真机上测试开启硬件加速查找问题
硬件加速的级别
Application <application android:hardwareAccelerated="true" ...>
Activity
<application android:hardwareAccelerated="true">
<activity ... />
<activity android:hardwareAccelerated="false" />
</application>
Window
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
View
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Note: 你可以关闭View级别的硬件加速,但是你不能在View级别开启硬件加速,因为它还依赖其他的设置
两种获取是否支持硬件加速的方式
View.isHardwareAccelerated() returns true if the View is attached to a hardware accelerated window.
Canvas.isHardwareAccelerated() returns true if the Canvas is hardware accelerated
如果必须进行这样的验证,建议你在draw的代码块中使用:Canvas.isHardwareAccelerated(),因为如果一个View被attach到一个硬件加速的Window上,
即使没有硬件加速的Canvas,它也是可以被绘制的。比如:将一个View以bitmap的形式进行缓存
Android的绘制模型
开启硬件加速后,Android框架将采用新的绘制模型。
基于软件的绘制模型和基于硬件的绘制模型的区别:
应用程序调用invalidate()更新UI的某一部分,失效(invalidation)消息将会在整个视图层中传递,计算每个需要重绘的区域(即脏区域)。
然后Android系统将会重绘所有和脏区域有交集的view。很明显,这种绘图模式存在缺点:
1. 每个绘制操作中会执行不必要的代码。比如如果应用程序调用invalidate()重绘button,而button又位于另一个view之上,
即使该view没有变化,也会进行重绘。
2. 可能会掩盖一些应用程序的bug。因为android系统会重绘与脏区域有交集的view,所以view的内容可能会在没有调用invalidate()的情况
下重绘。这可能会导致一个view只有在其它view时失效才得到正确的行为。这种行为可能在每次修改应用的时候都会发生改变。
因此,你需要一直调用invalidate在你的自定义控件上,不管那些涉及到重绘的代码是否修改了数据或状态。
Note:android view 在属性值变化的时候会自动调用invalidate,比如一个TextView的颜色或者背景的变化。
Android系统仍然使用invalidate()和draw()来绘制view,但在处理绘制上有所不同。
Android系统记录绘制命令到显示列表,包含的视图层次的绘图输出,而不是立即执行绘制命令。
另一个优化就是Android系统只需记录和更新标记为脏(通过invalidate())的view。新的绘制模型包含三个步骤:
1. Invalidate the hierarchy
2. 记录和更新显示列表
3. 绘制显示列表
在这种模式下,你不能指望一个视图相交的肮脏的地区会执行其draw()方法。为了确保Android系统记录视图的显示列表,你必须调用
invalidate()。否则会导致View不会刷新。
使用显示列表对动画的性能也会有好处,因为某些明确的属性,例如 alpha或者旋转,不要求invalidate目标View,(会自发的执行)。
这种优化也可以应用于所有显示列表的视图(当application硬件加速的时候)。
假设有一个LinearLayout,包含上述按钮列表。对于LinearLayout显示列表看起来像这样:
DrawDisplayList(ListView)
DrawDisplayList(Button)
假设你想改变ListView的透明度,在listview上调用了setAlpha之后,这个显示列表包括:
SaveLayerAlpha(0.5)
DrawDisplayList(ListView)
Restore
DrawDisplayList(Button)
ListView的复杂的draw代码块没有执行,相反,系统只会更新这个更简化的显示列表,如果应用中没有开启硬件加速,list和其父类的draw代码块
会再次执行。
硬件加速的2D渲染管道的建立是第一个支持不成比例的绘画,但是过高的值会影响到绘图操作的质量。
这些绘制的操作是按照1.0的规模纹理实现的,由GPU转化。在API级别<17,伴随着规模的增长会导致
如果你的应用程序是由任何这些特征缺失或限制的影响,你可以通过setLayerType(View.LAYER_TYPE_SOFTWARE, null).关闭它,不会影响到你再
别的地方使用硬件加速。
在所有版本的Android,所有的View具有渲染到锁屏缓冲区的能力,或通过View的绘制缓存,或者调用 Canvas.saveLayer().
锁屏缓冲区或者layers拥有几种用途。在实现复杂的动画或者应用于组件效果器的时候。比如, 实现退色效果:通过Canvas.saveLayer 临时的分发一个view到layer,
然后以一个不透明的参数返回.
在Android 3(API级别11开始),你有更多的控制如何以及何时使用层与视图setlayertype()方法。
这个API有两个参数:Layer的类型和一个可选的Paint,你可以使用Paint参数应用到颜色过滤器,特殊的混合模式,或者对于一个图层的不透明度。
视图可以使用三个layer类型:
LAYER_TYPE_NONE:
正常的使用,不会通过锁屏的缓冲区返回。
LAYER_TYPE_HARDWARE:
视图是由硬件实现为硬件机构如果应用硬件加速。如果应用程序没有硬件加速,这层型表现相同layer_type_software。
LAYER_TYPE_SOFTWARE:
layer的类型依赖于你的需求;
性能:
使用硬件层类型来渲染一个视图到纹理层,一旦视图被渲染成一层,其绘图代码不必执行,直到视图调用invalidate()执行。
一些动画,如α-动画,然后可以被直接应用到层,使用GPU来做是非常高效的。
视觉效应:
使用硬件或软件层型和涂料适用于特殊的视觉处理的观点。例如,你可以通过colormatrixcolorfilter画一个黑白相间的视图。
兼容性:
使用一个软件层类型去强制渲染一个视图。如果一个被硬件加速的视图(例如,如果你的整个应用程序的硬件加速),就会出现
渲染的问题,这是一个解决硬件渲染管线限制的简单的方法。
当你的应用程序的硬件加速,硬件层可以提供更快和更平滑的动画。
在每秒60帧运行一个处理大量绘图操作的复杂动画有时候是不可能的。
这可以通过使用硬件层渲染为硬件纹理缓解。然后硬件纹理可以用来制作视图的动画,不需要视图在动画的时候不断重绘自己。视图不被重绘,
除非你改变视图的属性,调用了invalidate(),或者你手动的调用invalidate,你将不会得到一个平滑的动画。这时你需要考虑开启硬件层应用
到你的动画。
当一个视图是由硬件层的支持,它的一些属性通过layer被合成到屏幕的方式处理。
设置这些属性将是有效的因为他们不需要视图invalidate和重绘。下面列出的属性影响layer合成的方式
alpha:
Changes the layer's opacity
x, y, translationX, translationY:
Changes the layer's position
scaleX, scaleY:
Changes the layer's size
rotation, rotationX, rotationY:
Changes the layer's orientation in 3D space
pivotX, pivotY:
Changes the layer's transformations origin
因为硬件层使用视频内存,它是高度推荐你在启动动画的时候开启它们,在动画完成的时候关闭它们。
Tip & Tricks
切换硬件加速的2D图形可以立即提高性能,但你仍应该遵循以下建议以便有效地利用GPU应用程序
减少应用程序中的View的数量
需要绘制的视图越多,它的速度就越慢。这同样适用于软件渲染。减少视图是一个简单的方法来优化您的UI。
避免透支
不在彼此的顶部画太多的层次。移除任何被它上面不透明的视图完全遮盖的视图。如果你需要绘制几层的混合在一起,把它们合并为一个单一的层。
对于当前的硬件,一个好的经验法则是不在屏幕上画出每帧的像素数超过2.5次(在一个位图透明像素计数!)。
不要创建渲染对象的绘制方法
一个常见的错误是,每一次渲染方法被调用的时候都创建一个新的Paint或一个新的Path。这迫使垃圾收集器运行更加频繁,也绕过缓存优化的硬件管道。
不要太频繁的修改形状
复杂的形状,Path,Circle,每次都是通过texture masks来渲染的,每次创建或者修改Path,这个硬件管道会创建一个新的mask,而这时十分昂贵的。
不要太频繁的修改Bitmap
每次改变Bitmap的内容,都会作为一个GPU texture再次上传,然后下次重新绘制。
谨慎使用alpha
当你使用setAlpha,AlphaAnimation或者ObjectAnimator实现一个透明的View时,它会在一个双倍的填充率的离屏的缓冲区渲染。