在Android3.0后,Android的2D渲染通道开始支持硬件加速,也就是说所有View的Canvas绘画动作都会使用GPU,同时也代表着应用程序会损耗更多的内存。而在Android4.0(API14)之后硬件加速功能就被默认开启了。如果你的应用程序是由各种标准View和Drawable组成的,那么硬件加速并不会引起任何不适。众所周知,使用硬件加速会调用到OpenGL,但是OpenGL不同版本会存在不支持一些操作的情况,也就是说,硬件加速可能会影响一些自定义View及绘制过程。因此,Android系统提供了关闭硬件加速的方法,好的消息是,可以在不同层级上对硬件加速功能进行控制,而不至于整个应用程序因为某一个绘制动作的障碍而整体都不能使用硬件加速,毕竟硬件加速能够带来更加流畅、更加绚丽的界面效果。
PS:列表有错位,标题向后移动一个
API level |
||||
< 16 | 16 | 17 | 18 | |
Canvas | ||||
drawBitmapMesh() (colors array) | ✗ | ✗ | ✗ | ✓ |
drawPicture() | ✗ | ✗ | ✗ | ✗ |
drawPosText() | ✗ | ✓ | ✓ | ✓ |
drawTextOnPath() | ✗ | ✓ | ✓ | ✓ |
drawVertices() | ✗ | ✗ | ✗ | ✗ |
setDrawFilter() | ✗ | ✓ | ✓ | ✓ |
clipPath() | ✗ | ✗ | ✗ | ✓ |
clipRegion() | ✗ | ✗ | ✗ | ✓ |
clipRect(Region.Op.XOR) | ✗ | ✗ | ✗ | ✓ |
clipRect(Region.Op.Difference) | ✗ | ✗ | ✗ | ✓ |
clipRect(Region.Op.ReverseDifference) | ✗ | ✗ | ✗ | ✓ |
clipRect() with rotation/perspective | ✗ | ✗ | ✗ | ✓ |
Paint | ||||
setAntiAlias() (for text) | ✗ | ✗ | ✗ | ✓ |
setAntiAlias() (for lines) | ✗ | ✓ | ✓ | ✓ |
setFilterBitmap() | ✗ | ✗ | ✓ | ✓ |
setLinearText() | ✗ | ✗ | ✗ | ✗ |
setMaskFilter() | ✗ | ✗ | ✗ | ✗ |
setPathEffect() (for lines) | ✗ | ✗ | ✗ | ✗ |
setRasterizer() | ✗ | ✗ | ✗ | ✗ |
setShadowLayer() (other than text) | ✗ | ✗ | ✗ | ✗ |
setStrokeCap() (for lines) | ✗ | ✗ | ✗ | ✓ |
setStrokeCap() (for points) | ✗ | ✗ | ✗ | ✗ |
setSubpixelText() | ✗ | ✗ | ✗ | ✗ |
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 | ✗ | ✗ | ✗ | ✓ |
引言中说过控制硬件加速可以在不同层级进行,这样可以避免因为一个绘制动作不支持而导致整个应用都不可以使用硬件加速这样很愚蠢的情况发生。总共有四个层级,从上到下是:
1. Application
应用程序等级控制硬件加速,在AndroidManifest.xml中进行:
<application android:hardwareAccelerated="true" ...>
2. Activity
Activity等级的控制方法还是在AndroidManifest.xml中进行,如下展示了应用整体使用硬件加速,而某一个Activity不使用的例子:
<application android:hardwareAccelerated="true"> <activity ... /> <activity android:hardwareAccelerated="false" /> </application>
3. Window
窗口级控制,如果只是想让某个窗口使用硬件加速:
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
4. View
可以通过代码在运行时控制单个View是否使用硬件加速:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
何时关闭?关闭谁?
可以通过
View.isHardwareAccelerated()和
Canvas.isHardwareAccelerated()检测其是否在使用硬件加速。如果是自定义View,通过复写onDraw改变Canvas内容,那么最好的检测Canvas而非View,即使一个View被放置到了使用硬件加速的Window中,View本身及Canvas仍然可以不使用硬件加速功能。所以,在合适的位置进行关闭,关闭该关闭的那个对象很重要。