前言:
不应该一路失望
又一路等待
时间它说
世界还有不同的海
但不要告诉我
现实它很坏
我想看看
自己的能耐
——莫文蔚《境外》
系列文章:
Android自定义控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268
一、GPU硬件加速
1、概述
GPU英文全称Graphic Processing Unit,中文翻译为“图形处理器”。与CPU不同,GPU是专门为处理图形任务而产生的芯片。
在GPU出现之前,CPU一直负责着所有的运算工作,CPU的架构是有利于X86指令集的串行架构,CPU从设计思路上适合尽可能快的完成一个任务。但当面对类似多媒体、图形图像处理类型的任务时,就显得力不从心。因为在多媒体计算中通常要求更高的运算密度、多并发线程和频繁地存储器访问;显然当你打游戏时,屏幕上的动画是需要实时刷新的,这些都需要频繁的计算、存取动作;如果CPU不能及时响应,那么屏幕就会显得很卡……你的队友可能会发一句……我等的花都谢了,你咋还不动呢……
为了专门处理多媒体的计算、存储任务,GPU就应运而生了,GPU中自带处理器和存储器,以用来专门计算和存储多媒体任务。
对于Andorid来讲,在API 11之前是没有GPU的概念的,在API 11之后,在程序集中加入了对GPU加速的支持,在API 14之后,硬件加速是默认开启的!我们可以显式地强制图像计算时使用GPU而不使用CPU.
在CPU绘制和GPU绘制时,在流程上是有区别的:
在基于软件的绘制模型下,CPU主导绘图,视图按照两个步骤绘制:
- 让View层次结构失效
- 绘制View层次结构
在基于硬件加速的绘制模式下,GPU主导绘图,绘制按照三个步骤绘制:
- 让View层次结构失效
- 记录、更新显示列表
- 绘制显示列表
可以看到在GPU加速时,流程中多了一项“记录、更新显示列表”,它表示在第一步View层次结构失效后,并不是直接开始逐层绘制,而是首先把这些View的绘制函数作为绘制指令记录一个显示列表中,然后再读取显示列表中的绘制指令调用OpenGL相关函数完成实际绘制。所以在GPU加速时,实际是使用OpenGL的函数来完成绘制的。
所以使用GPU加速的优点显而易见:硬件加速提高了Android系统显示和刷新的速度;
它有缺点也显而易见:
1、 兼容性问题:由于是将绘制函数转换成OpenGL命令来绘制,定然会存在OpenGL并不能完全支持原始绘制函数的问题,所以这就会造成在打开GPU加速时,效果会失效的问题。
2、内存消耗问题:由于需要OpenGL的指令,所以需要把系统中的OpenGL相关的包加载到内存中来,所以单纯OpenGL API调用就会占用8MB,而实际上会占用更多内存;
3、电量消耗问题:多使用了一个部件,当然会更耗电……
下图显示了一些特殊函数硬件加速开始支持的平台等级:(红叉表示任何平台都不支持,不在列表中的默认在API 11就开始支持)
图片摘自《google官方文档:硬件加速》
我再重复一遍,上面我们涉及了两个API等级,在API 11以后,在程序集中加入了对GPU加速的支持,在API 14之后,硬件加速是默认开启的!也就是说在API 11——API 13虽然是支持硬件加速的,但是默认是关闭的。
2、禁用GPU硬件加速方法
那么问题就来了,如果你的APP跑在API 14版本以后,而你洽好要用那些不支持硬件加速的函数要怎么办?
那就只好禁用硬件加速喽,针对不同类型的东东,Android给我们提供了不同的禁用方法:
硬件加速分全局(Application)、Activity、Window、View 四个层级
1.在AndroidManifest.xml文件为application标签添加如下的属性即可为整个应用程序开启/关闭硬件加速:
<application android:hardwareAccelerated="true" ...>
2.在Activity 标签下使用 hardwareAccelerated 属性开启或关闭硬件加速:
<activity android:hardwareAccelerated="false" />
3. 在Window 层级使用如下代码开启硬件加速:(Window层级不支持关闭硬件加速)
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
4.View 级别如下关闭硬件加速:(view 层级上不支持开启硬件加速)
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
或者使用android:layerType=”software”来关闭硬件加速:比如
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingLeft="2dp"
android:layerType="software"
android:paddingRight="2dp" >
二、setXfermode(Xfermode xfermode)之AvoidXfermode
这个函数是图像混合里最难的一个了,它的功能也是相当强大的,这个模式叫做图形混合模式。
与setColorFilter一样,派生自Xfermode的有三个类:
1、概述——基本流程
从上面可以看出,派生自Xfermode的有AvoidXfermode,PixelXorXfermode,PorterDuffXfermode;
从硬件加速不支持的函数列表中,我们可以看到AvoidXfermode,PixelXorXfermode是完全不支持的,而PorterDuffXfermode是部分不支持的。
所以在使用Xfermode时,为了保险起见,我们需要做两件事:
1、禁用硬件加速:
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
2、使用离屏绘制
//新建图层
int layerID = canvas.saveLayer(0,0,width,height,mPaint,Canvas.ALL_SAVE_FLAG);
//TODO 核心绘制代码
//还原图层
canvas.restoreToCount(layerID);
有关离屏绘制的原因,这节就先不给大家引申了,后面会单独拉出来两篇文章讲离屏绘制,大家只需要知道,我们需要把绘制的核心代码放在saveLayer()和restoreToCount()之间即可。
下面我们先简单讲解AvoidXfermode的用法,然后写个例子,看下SetXfermode()的使用方法和效果
AvoidXfermode的声明如下:
public AvoidXfermode(int opColor, int tolerance, Mode mode)
当Mode取Mod