今天来分析一下视图优化,首先解释一下GPU过度绘制的概念,GPU过度绘制指的是在屏幕一个像素上绘制多次(超过一次),比如一个TextView后有背景,那么显示文本的像素至少绘了两次,一次是背景,一次是文本。
颜色标识: GPU过度绘制从好到差:蓝-绿-淡红-红
- 蓝色1x过度绘制
- 绿色2x过度绘制
- 淡红色3x过度绘制
- 红色超过4x过度绘制
GPU过度绘制或多或少对性能有些影响,所以我们应该尽量不要让我们的界面不要出现红色,否则对性能影响很大,影响用户体验。
准备工具:
- Android 4.2+设备
- Android Studio 1.5+
- AndroidUIPorblems下载地址
开始分析:
1.首先在开发者选项中把GPU过度绘制打开,运行项目,查看效果。
可以看到屏幕上的颜色,分别代表了上面所说的过度绘制级别,非常直观的显示了问题所在,现在我们直奔代码,开始进行优化修改。
由于有窗体默认会有背景色存在,但是我们现在自定义了背景,完全不需要window自带的背景,这时候可以使用getWindow().setBackgroundDrawable(null);把window的背景去除,看起来很不错,颜色比刚才好了一些,接下来继续寻找可以优化的地方。
经过寻找唯一可以优化的地方只有TextView控件的背景了,如果没必要,可以去除。这里就不演示修改后的结果了,下面进入OverDrawView看看有什么需要优化的地方,看起来过度绘制现象很严重。
看一下绘图的代码,原来在填充矩形时发生重复了,修改一下就OK了,同样不要忘记了把window的背景设置为null;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
mPaint.setColor(Color.GRAY);
canvas.drawRect(0, 0, width, height, mPaint);
mPaint.setColor(Color.CYAN);
canvas.drawRect(0, height/4, width, height, mPaint);
mPaint.setColor(Color.DKGRAY);
canvas.drawRect(0, height/3, width, height, mPaint);
mPaint.setColor(Color.LTGRAY);
canvas.drawRect(0, height/2, width, height, mPaint);
}
代码修改如下:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
mPaint.setColor(Color.GRAY);
canvas.drawRect(0, 0, width, height/4, mPaint);
mPaint.setColor(Color.CYAN);
canvas.drawRect(0, height/4, width, height/3, mPaint);
mPaint.setColor(Color.DKGRAY);
canvas.drawRect(0, height/3, width, height/2, mPaint);
mPaint.setColor(Color.LTGRAY);
canvas.drawRect(0, height/2, width, height, mPaint);
}
最终效果如图所示,不存在过度绘制的情况了。
最后看一下BusyOnDraw的情况,截图无法展现出效果,因为程序在跳转时会卡住几秒钟,直接看代码,发现在onDraw函数里面做了非常耗时的操作,所以很好解决,开启一个线程做可以了。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < 1000; i++) {
System.out.println("canvas = [" + canvas + "]" + i); }
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(4);
int radius = Math.min(getWidth(), getHeight()) / 2;
canvas.drawCircle(getWidth()/2, getHeight()/2, radius, paint);
}
代码修改如下:
- 成员变量:
private Handler mHandler=new Handler();
private Paint mPaint = new Paint();
- onDraw:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mHandler.post(doBusyThing(canvas));
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4);
int radius = Math.min(getWidth(), getHeight()) / 2;
canvas.drawCircle(getWidth()/2, getHeight()/2, radius, mPaint);
}
- 添加doBusyThing方法:
private Runnable doBusyThing(final Canvas canvas){
return new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("canvas = [" + canvas + "]" + i);
}
}
};
}
OK修改完成,这个项目已经没有问题了,这篇文章到此结束了。