Hardware Acceleration
在Android 3.0的(API级别11)开始,Android的2D渲染管线支持硬件加速,这意味着那些在View的画布进行的所有绘制操作使用GPU。由于启用硬件加速所需增加的资源,你的应用程序会消耗更多的内存。
硬件加速,默认情况下,如果你的目标API级别为> = 14,但也可以显式启用启用。如果应用程序使用的唯一标准的观点和绘图,将其打开全球范围内应该不会造成任何不利的绘图效果。但是,由于硬件加速不支持所有的2D绘图操作,将其打开,可能会影响你的一些自定义视图或绘图电话。问题往往表现为不可见元素,异常或错误渲染像素。为了解决这个问题,Android为您提供启用或禁用多层次的硬件加速的选项。请参阅控制硬件加速。
如果您的应用程序进行自定义绘制,测试与硬件加速实际硬件设备的应用程序打开,以发现任何问题。不支持的绘制操作部分介绍了硬件加速,以及如何解决它们的已知问题。
控制硬件加速
您可以控制??在以下级别的硬件加速:
- Application
- Activity
- Window
- View
在你的Andr??oid清单文件,下面的属性添加到<应用程序>标签来启用硬件加速整个应用程序:
<application android:hardwareAccelerated="true" ...>
活动水平
如果您的应用不能正常使用硬件加速的行为开启全球范围内,你可以控制它的个人活动为好。要启用或在活动层次禁用硬件加速,可以使用android:hardwareAccelerated属性为<活动>元素。下面的示例启用硬件加速整个应用程序,但禁用它的一个活动:
<application android:hardwareAccelerated="true"> <activity ... /> <activity android:hardwareAccelerated="false" /> </application>
窗位
如果您需要更细粒度的控制,您可以为下面的代码给定的窗口硬件加速:
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
意:您目前不能在窗口级别禁用硬件加速。
查看水平
您可以在下面的代码运行时个人的看法禁用硬件加速
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
注意:您目前不能启用在视图级别的硬件加速。查看层具有除禁用硬件加速等功能。请参见视图层关于其用途的更多信息。
确定一个观点是硬件加速
它有时是有用的应用程序知道它是否是目前硬件加速,尤其是对的东西,如自定义视图。如果你的应用做了很多自定义绘制的,而不是所有的操作都??是由新的渲染管线适当的支持这是特别有用。
有两种不同的方法来检查应用程序是否是硬件加速:
如果View附属于硬件加速窗口View.isHardwareAccelerated()返回true。
如果画布是硬件加速Canvas.isHardwareAccelerated()返回true
如果你必须做这个检查你的绘制代码,尽可能使用Canvas.isHardwareAccelerated(),而View.isHardwareAccelerated()。当一个视图被连接到一个硬件加速窗口,它仍可以使用非硬件加速画布绘制。发生这种情况,例如,拉拔一个视图成用于高速缓存目的的位图时。
Android的图纸模型
当启用硬件加速,Android框架利用,利用显示列表呈现您的应用程序到屏幕上一个新的绘图模式。要充分认识显示列表以及它们如何影响您的应用程序,必须了解Android的如何绘制看法,并没有硬件加速也非常有用。以下部分描述了基于软件和硬件加速绘制的模型。
基于软件的绘图模型
在软件绘图模型,视图画出具有以下两个步骤:
无效的层次
绘制层次
当一个应用程序需要更新其用户界面的一部分,它调用无效()(或其变体之一)对已更改内容的任何看法。无效的消息被传播一路视图层次结构来计算屏幕需要重绘(脏区)的区域。然后,Android系统绘制在与脏区相交的层次中的任何视图。不幸的是,有两个缺点该图模型:
首先,这种模式需要在每次抽奖通大量的代码的执行。例如,如果您的应用程序调用无效()上的一个按钮,该按钮坐在另一种观点之上,Android系统重绘,即使它并没有改变的观点。
第二个问题是,图纸模型可以隐藏在应用程序中的错误。由于Android系统的重绘意见时,他们相交脏区,以便您更改其内容即使无效可能重绘()不叫就可以了。发生这种情况时,你是靠另一种观点被无效,以获得正确的行为。这种行为可以改变你每次修改应用程序的时间。正因为如此,你应该总是调用无效()在您的自定义视图只要您修改影响了视图的绘制代码数据或状态。
注:Android的观点自动调用无效()时,他们的性质改变,如背景颜色或在一个TextView的文本。
硬件加速绘图模型
Android系统仍然使用无效(),并绘制()请求屏幕更新和渲染的看法,但不同的方式处理实际的绘制。而不是执行绘制命令,立即,Android系统将它们记录显示列表,其中包含视图层次的绘制代码的输出里面。另一种优化是Android系统只需要记录和更新显示列出了意见标志着一个无效()调用脏。还没有被无效的观点可以简单地通过重新发出先前记录的显示列表被重绘。新的绘图模型包含三个阶段:
无效的层次
记录和更新显示列表
绘制显示列表
在这种模式下,你可以不依赖于交叉脏区有其draw()方法执行视图。为了确保Android系统记录一个视图的显示列表,你必须调用无效()。忘了这样做的原因,以便看看它已被更改即使是相同的。
使用显示表也有利于动画性能,因为设置特定性质,例如α-或旋转,不需要无效目标图(它是自动完成的)。这个优化也适用于显示列表视图(当你的应用程序的硬件加速的任何观点。)例如,假设有一个包含按钮上方一个ListView一个LinearLayout中。为的LinearLayout显示列表如下:
DrawDisplayList(ListView控件)
DrawDisplayList(按钮)
现在假设你想改变ListView的不透明性。在调用的ListView setAlpha(0.5F)后,显示列表现在包含这样的:
SaveLayerAlpha(0.5)
DrawDisplayList(ListView控件)
恢复
DrawDisplayList(按钮)
ListView中的复杂的绘制代码没有被执行。取而代之的是,系统只更新了简单得多的LinearLayout的显示列表。在没有硬件加速的应用程序启用后,名单及其父两者的绘制代码再次执行。
不支持的绘图操作
当硬件加速时,2D渲染管线,支持最常用的画布绘制操作以及许多不太使用的操作。所有这一切都用来渲染与Android,默认的部件和布局,共同先进的视觉效果,如反射和瓷砖纹理船舶应用的绘制操作的支持。
下表描述了整个API级别的各种操作的支撑位:
First supported API level | ||||
Canvas | ||||
drawBitmapMesh() (colors array) | 18 | |||
drawPicture() | 23 | |||
drawPosText() | 16 | |||
drawTextOnPath() | 16 | |||
drawVertices() | ? | |||
setDrawFilter() | 16 | |||
clipPath() | 18 | |||
clipRegion() | 18 | |||
clipRect(Region.Op.XOR) | 18 | |||
clipRect(Region.Op.Difference) | 18 | |||
clipRect(Region.Op.ReverseDifference) | 18 | |||
clipRect() with rotation/perspective | 18 | |||
drawArc() | 21 | |||
drawRoundRect() | 21 | |||
saveLayer() with RectF dimensions | 21 | |||
saveLayer() with float dimensions | 21 | |||
saveLayerAlpha() with RectF dimensions | 21 | |||
saveLayerAlpha() with float dimensions | 21 | |||
Paint | ||||
setAntiAlias() (for text) | 18 | |||
setAntiAlias() (for lines) | 16 | |||
setFilterBitmap() | 17 | |||
setLinearText() | ? | |||
setMaskFilter() | ? | |||
setPathEffect() (for lines) | ? | |||
setRasterizer() | ? | |||
setShadowLayer() (other than text) | ? | |||
setStrokeCap() (for lines) | 18 | |||
setStrokeCap() (for points) | 19 | |||
setSubpixelText() | ? | |||
getFontFeatureSettings() | 21 | |||
isElegantTextHeight() | 21 | |||
isElegantTextHeight() | 21 | |||
setFontFeatureSettings() | 21 | |||
setLetterSpacing() | 21 | |||
Xfermode | ||||
AvoidXfermode | ? | |||
PixelXorXfermode | ? | |||
PorterDuff.Mode.DARKEN (framebuffer) | ? | |||
PorterDuff.Mode.LIGHTEN (framebuffer) | ? | |||
PorterDuff.Mode.OVERLAY (framebuffer) | ? | |||
Shader | ||||
ComposeShader inside ComposeShader | ? | |||
Same type shaders inside ComposeShader | ? | |||
Local matrix on ComposeShader | 18 |
画布缩放
硬件加速2D渲染管线建成第一个支持缩放的绘图,一些绘图操作在更高的刻度值显著降低质量。这些操作被实现为大规模1.0绘制纹理,由GPU转化。在API级别<17,使用这些操作都会导致结垢文物与规模越来越大。
下表显示了当执行改为正确处理大尺度:
Drawing operation to be scaled | First supported API level |
drawText() | 18 |
drawPosText() | ? |
drawTextOnPath() | ? |
Simple Shapes* | 17 |
Complex Shapes* | ? |
drawPath() | ? |
Shadow layer | ? |
Drawing operation to be scaled | First supported API level |
drawText() | 18 |
drawPosText() | ? |
drawTextOnPath() | ? |
Simple Shapes* | 17 |
Complex Shapes* | ? |
drawPath() | ? |
Shadow layer | ? |
注意:“简单”形状的drawRect(),画圆(),drawOval(),drawRoundRect(),和drawArc()(与useCenter =假)用涂料发出的命令,不具有PathEffect,并且不包含非默认的连接(通过setStrokeJoin()/ setStrokeMiter())。那些其他实例绘制命令如上图下摔倒‘情结‘。
如果你的申请是由任何这些缺失的功能或限制的影响,可以通过调用setLayerType(View.LAYER_TYPE_SOFTWARE,NULL)关闭硬件加速您的应用程序只是受影响的部分。这样,你仍然可以利用硬件加速的优势,其他任何地方。请参阅控制硬件加速有关如何启用和不同层次的应用程序禁用硬件加速的更多信息。
查看图层
在Android中的所有版本,有意见,可以通过使用视图的绘图缓存,或使用Canvas.saveLayer()不得不呈现到屏幕外缓冲区的能力。屏幕外缓冲区,或层,有几个用途。您可以使用这些复杂的动画视图时获得更好的性能和应用组成的影响。例如,您可以实现使用Canvas.saveLayer()暂时呈现视图成层褪色效果,然后综合其重新打开屏幕不透明的因素。
在Android 3.0的(API级别11)开始,您对如何以及何时使用层与View.setLayerType()方法更多的控制。此API有两个参数:要使用层的种类和描述的层应如何合成的可选油漆对象。您可以使用画图参数彩色滤光片,特殊的混合模式或不透明度应用到图层。视图可以使用三层类型之一:
LAYER_TYPE_NONE:视图通常呈现的,而不是由一个离屏缓冲区支持。这是默认的行为。
LAYER_TYPE_HARDWARE:视图渲染为硬件到硬件纹理,如果应用程序的硬件加速。如果应用程序没有硬件加速,这层类型的行为一样LAYER_TYPE_SOFTWARE。
LAYER_TYPE_SOFTWARE:视图渲染软件成位图。
层的使用类型取决于你的目标:
性能:使用硬件层式渲染视图到硬件的质感。一旦视图渲染成层,它的绘制代码没有被执行,直到视图调用无效()。一些动画,如α动画,然后可以直接施加到层,这是非常有效的针对GPU做。
视觉效果:使用硬件或软件层类型和画图特殊的视觉处理应用到视图。例如,你可以画在黑色和白色使用ColorMatrixColorFilter视图。
兼容性:使用一个软件层类型强制在软件中呈现的图。如果是硬件加速(举例来说,如果你的整个应用程序的硬件acclerated)视图,是有渲染问题,这是一个简单的方法来解决硬件渲染管线的限制。
查看层和动画
当你的应用程序的硬件加速硬件层可以提供更快和更流畅的动画。以每秒60帧运行的动画动画这个问题很多绘图操作复杂视图时,并不总是可能的。这可以通过使用硬件层呈现视图给硬件纹理得到缓解。然后,硬件质地可用于动画视图,省去了视图不断重绘自身时被动画吧。该观点是不重绘,除非您更改视图的属性,它调用无效(),或者如果你调用无效(手动)。如果您运行的应用程序中的动画,并没有获得想要的结果顺利,考虑你的意见动画硬件实现层。
当视图是由硬件层的支持,它的一些属性由层屏幕上合成的方式处理。设置这些属性将是有效的,因为它们不要求将被无效和重新绘制的图。以下属性的列表影响层合成的方式。呼吁任何最佳无效和没有针对性的观点重新划分这些属性结果的二传手:
阿尔法:改变图层的不透明度
X,Y,translationX,translationY:改变图层的位置
将scaleX,的scaleY:改变层的大小
旋转的rotationX,的rotationY:改变层的三维空间定位
pivotX,pivotY:改变层的转换起源
这些性质是动画与ObjectAnimator的图时所使用的名称。如果要访问这些属性,调用相应的setter或getter。例如,修改alpha属性,调用setAlpha()。下面的代码片段展示了最有效的方式绕Y轴的3D旋转的viewiew:
view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator.ofFloat(view, "rotationY", 180).start();
因为硬件层消耗显存,强烈建议您让他们只为动画的持续时间,然后禁用这些动画完成后。你可以做到这一点使用动画听众:
View.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(View.LAYER_TYPE_NONE, null); } }); animator.start();
有关属性动画的更多信息,请参见属性动画。
技巧和窍门
切换到硬件加速2D图形可以瞬间提高性能,但你还是应该遵循这些建议有效地设计你的应用程序使用的GPU:
减少你的应用程序的若干意见
该系统具有绘制更多的意见,越慢会。这适用于软件渲染管线以及。减少的观点是,以优化你的用户界面的最简单的方法之一。
避免透支
不要借鉴彼此顶部太多层。删除完全由在它上面的其他不透明的观点掩盖任何意见。如果您需要绘制混合在彼此顶部几层,把它们合并成一个单一的层。与当前的硬件一个好的经验法则是不能吸引超过2.5倍的每帧画面的像素(位图中透明的像素数!)的数量。
不要创建渲染绘制方法的对象
一个常见的??错误是创建一个新的油漆或每次调用的绘制方法的时间了一条新路。这迫使垃圾收集更频繁地运行,也绕过缓存和优化硬件管道。
不要修改形状过于频繁
复杂形状,路径,并且例如圆,使用纹理掩模渲染。创建或修改的路径每次,硬件管道创建一个新的掩模,其可以是昂贵的。
不要修改位图太频繁
每次你改变一个位图的内容时,它再次绘制它的下一次上传为GPU的纹理。
使用Alpha小心
当你使用setAlpha(),AlphaAnimation或ObjectAnimator使视图半透明,它在双打所需的填充率一个离屏缓冲呈现。当在非常大的意见将α,考虑到视图层类型设置为LAYER_TYPE_HARDWARE。
Drawing operation to be scaled | First supported API level |
drawText() | 18 |
drawPosText() | ? |
drawTextOnPath() | ? |
Simple Shapes* | 17 |
Complex Shapes* | ? |
drawPath() | ? |
Shadow layer | ? |