Android 4.0硬件加速及绘制技巧
从Android 3.0开始,Android 2D的绘制流程就设计为能够更好地支持硬件加速。使用GPU的View在Canvas上进行画的操作时都会使用硬件加速。在最新的Android版本里,图形硬件加速及绘制技巧得到了更好的提升.
Android 4.0
1.Android 4.0硬件加速的使用
1.1 硬件加速的控制级别
启用硬件加速的最简单方法就是为整个系统打开硬件加速的全局设置。如果你的程序是标准View或者是Drawable 则硬件加速的全局设这并不会造成不良的影响。然而硬件加速并不支持所有2D画的操作,所以开启硬件加速可能会对使用自定义组件的应用程序造成影响,问题常常表现在不可见的元素异常和错误的像素渲染,为了解决这个问题Android可以让你选择启动或者禁用以下级别的硬件加速:Application Activity Window 和 View 。
1.1.1 Application级别
在你的Android Manifest文件中添加 属性标记,以便为整个应用程序使用硬件加速。
1.1.2 Activity级别
如果你的应用程序不能在Application应用级别表现良好的话,则可以使用对Activity进行单独控制。要启动或者禁用一个Activity的硬件加速,你可以使用activity的android:hardwareAccelerated属性。下面的一个列子使整个Application启用硬件加速,但是对一个Activity禁止使用硬件加速。
1.1.3 Window级别
如果你需要更细粒度的控制,你可以通过如下代码给window进行加速。
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
注意:现阶段你不能在Window级别对它禁用硬件加速。
1.1.4 View级别
我们可以对单独的View在运行时阶段禁用硬件加速。我们可以使用如下代码:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
注意:现阶段不能够在View级别进行硬件加速。
1.2 判断一个View是否已经启用了硬件加速
有时候我们需要知道一个应用程序是否已经启用了硬件加速,特别是针对一些自定义控件。因为你的应用程序做了很多自定义“画”的操作,但并不是所有的过程都支持新的“画”的渲染过程。
有两种不同的方法来检查Application是否启用了硬件加速:
1.2.1 使用View.isHardwareAccelerated() 如果返回true则可以说明这个View所在的窗口已经启用了硬件加速。
1.2.2 Canvas.isHardwareAccelerated() 如果返回true则说明这个Canvas已经启用了硬件加速。
如果你必须要在你的绘画代码中进行是否已经加速的检查,如果可能的话请使用Canvas.isHardwareAccelerated()来代替View.isHardwareAccelerated()。当一个View是存在于一个已经加速的Windows上时,任然可以使用没有硬件加速的Canvas进行绘画,这场发生在,比如,当我们把一个View画到Bitmap上然后用作缓存。
2.Android 4.0的绘制模型
当开启了硬件加速,Android框架将会使用一种新的绘制模型,这种模型将会使用显示列表把你的应用显示到屏幕上。要完全理解显示列表和他们如何影响你的应用程序,理解Android 4.0如何在非硬件加速的情况下如何绘制Views是很有必要的,下面将分别介绍软件加速和硬件加速。
2.1基于软件的绘制模型
在基于软件绘制模型中,View的绘制遵循以下两步:1.使整个控件层级无效。2.对层级进行绘制。
当一个应用程序需要更新它UI的一部分时,它将会调用内容发生改变的View的invalidate()方法(或者invalidate的变体)。Invalidate的消息按照View的层级关系向上传递用以计算需要重画的部分(即脏区域)。然后Android系统会对和脏区域有交集的所有View进行绘制,不幸的是这种模型中有两个缺点:
2.1.1 在这种模型中当在不同的层进行画的时候,会额外执行很多代码。例如一个Button是位于另外一个View之上,当对Button调用 Invalidate()时,Android就会对这个View进行重绘,即便这个View没有发生任何变化。
2.1.2 第二个问题是这种绘制模型会隐藏你Application中的Bug。因为Android系统会对和脏区域有交集的View进行重绘,在这种情况下如果一个view的内容发生了改变,即便这个View的Invalidate()的方法并没有得到调用,它也可能被重绘。你便会依赖调用了invalidate()的其他的控件以便获得正确的行为,因此每当你的Application发生改变时,这种行为多要随之发生改变。也是基于次因,在你的自定义控件中你必须不断地调用invalidate()方法,当你的数据或者是状态会影响View的绘制代码时。
注意:Android的View当它们的属性发生改变时会自动的调用Invalidate()。比如,你改变一个 Textview的背景或者是它的文本。
2.2 基于硬件加速模型
Android 系统仍然通过invalidate()和draw()去请求屏幕更新和重新渲染,但是实际处理画的方式是不同的。不是立即执行画的命令,Android而会将所有画的命令记录在一个显示列表里面,这个显示列表包含了输出的View层级的绘制代码。还有一个优化就是Android在显示列表中只会记录和更新显示层级中通过调用invalidate()函数被标记为“脏”的view。没有被请求刷新的view可以通过重新请求先前的显示列表以便重画。新的绘制模型包括有三个步骤:1.禁用整个View层级。2.记录和更新显示列表。3.绘制显示列表。
使用这个模型你不能依赖一个View和脏区域有交集就会执行draw()方法。要确保Android系统记录了一个View的显示列表,你必须调用invalidate()方法,如果忘记了调用刷新,会使View即便是发生了改变后也会看起来相同,这是一个比较容易发现bug的方式。
使用显示列表的方式对动画的表现也是很有好处的,因为设置指定的属性值,比如透明度或者旋转,就不需要请求刷新目标View(这将自动执行)。这项优化也应用于有显示列表的Views(启用了硬件加速的View),例如,现在有一个LinearLayout包含了一个ListView和Button,listview在button的上面。这时候LinearLayout的显示列表如下所示:
◆DrawDisplayList(ListView) ;
◆DrawDisplayList(Button) ;
假设你现在你想更新这个Listview的不透明度,在设置Listview的 setAlpha(0.5f) 属性之后,LinearLayout的显示列表应该包含如下:
◆ SaveLayerAlpha(0.5)
◆ DrawDisplayList(ListView)
◆ Restore
◆ DrawDisplayList(Button)
这时候绘制Listview的复杂过程就会省略了,取而代之的是简单的更新了LinearLayout的显示列表。如果一个应用程序并没有启用硬件加速,Listview和它的父view的画的代码都会重新执行。
3.Android 4.0 View的层
3.1层的分类
所有的Android版本都有能力对离屏缓冲进行渲染,或者是使用View的绘制缓冲,或者是使用Canvas.saveLayer()函数。离屏缓冲或者Layer能够有很多种应用,例如能使处理复杂view的动画效果或者应用一些合成效果都有更好地表现。例如你可以通过Canvas.saveLayer()的方式来对View做一个渐入渐出效果同时把它渲染到Layer中,然后再加上不透明效果合成后显示到屏幕上。
由Android 3.0开始你就能够通过View.setLayerType()方法对何时以及如何使用层有了更多的控制,这个API具有两个参数一个是你想使用的层类型,另外一个是可选参数Paint表明了Layer是如何被叠加的。你可以把Paint参数应用到颜色过滤上,特别是混合模式或者是对一个layer进行不透明效果。一个View可以使用如下的三种layer类型之一:
◆ LAYER_TYPE_NONE: 这个View将被按普通的方式进行渲染,但是不会返回一个离屏的缓冲,这个是默认的行为。
◆ LAYER_TYPE_HARDWARE:如果这个应用被硬件加速的话,这个View将会在硬件中渲染为硬件纹理,如果应用程序并没有被硬件加速,则其效果和LAYER_TYPE_SOFTWARE是相同的。
◆ LAYER_TYPE_SOFTWARE: 此View 通过软件渲染为一个bitmap。
3.2 层的使用
使用层的类型取决于你的目的:
3.2.1 性能:使用硬件层来渲染一个View成为硬件纹理。一旦一个View被渲染为一个层,它的绘制代码将不会得到执行,直到你调用了invalidate()函数。对于一些动画,比如透明动画可以直接应用到一个层上,这是GPU最有效率的使用方式。
3.2.2 显示效果:使用硬件或者软件层和Paint来对一个View进行特殊的视觉处理,例如你可以对一个View通过使用ColorMatrixColorFilter来实现黑白效果。