CPU与GPU
CPU 的任务繁多,做逻辑计算外,还要做内存管理、显示操作,因此
在实际运算的时候性能会大打折扣,在没有 GPU 的时代,不能显示复
杂的图形,其运算速度远跟不上今天复杂三维游戏的要求。即使 CPU
的工作频率超过 2GHz 或更高,对它绘制图形提高也不大。这时 GPU
的设计就出来了, CPU 的控制器较为复杂,擅长各种复杂的逻辑运算,但不擅长数学尤其是浮点运算。
简单来说就是CPU将图形的计算公式传给GPU,也可理解为显卡,然后GPU拿到这个公式后就开始矢量图的绘制工作,Android 系统每隔 16ms 发出 VSYNC 信号 (1000ms/60=16.66ms) ,触发对 UI 进行渲染, 如果每次渲染都成功这样就能够达到流畅的画面所需要的 60fps ,为了能够实现 60fps ,这意味着计算渲染的大多数操作都必须在 16ms 内完成。如果很多帧都没有在这个时间内绘制完成,就会出来视觉上的卡顿现象。这也是60Hz 刷新频率由来。
过度绘制
概念:
GPU的绘制过程,类似于装修刷墙,一层一层的进行,并且16ms刷一次,每刷一遍就是一个图层,这样就会有图层覆盖的情况,下边的图层用户看不到,但其实GPU也已经进行了绘制。
过度绘制出现的原因
- 自定义控件中的 onDraw 方法做了多重绘制
- 布局层次太深,例如xml文件使用了迷之缩进,布局层叠太多,用户看不到的区域也进行了绘制,导致耗时增加
过渡绘制查看
开发者工具打开调试GPU过渡绘制
可以看到上边有很多颜色,颜色越浅,说明过度绘制越少,
- 蓝色部分,过渡绘制一次,就是无过渡绘制,只有一层
- 淡绿色 过渡绘制两次,说明有两层
- 淡红色 过度绘制三次
- 深红 过度绘制四次及以上
然后就各个击破进行优化就好了
过度绘制优化
- 减少背景重复
去掉单个activity的主题设置的属性
可以在setContentView之前getWindow().setBackgroundDrawable(null);
去掉所有activity主题设置中的属性
直接在styles.xml中设置<item name="android:windowBackground">@null</item>
- 使用裁减减少控件之间的重合部分
- 注意点:
1.能在一个平面显示的内容,尽量只用一个容器
2.尽可能把相同的容器合并merge
3.能复用的代码,用include处理,可以减少GPU重复工作
hierarchy view 查看布局结构图
在你的AndroidSDK的安装目录找到 Android\sdk\tools\monitor.bat,双击运行(运行前先在模拟器中启动项目,真机好像不太好使),切换到Hierarchy View ,找到自己的要查看的页面
这样就可以看到你的当前页面每个布局下一共有几层view了,试图减少view的层级可以提高GPU的渲染效率
自定义view裁剪被遮挡布局
public class DroidCardsView extends View {
//图片与图片之间的间距
private int mCardSpacing = 150;
//图片与左侧距离的记录
private int mCardLeft = 10;
private List<DroidCard> mDroidCards = new ArrayList<DroidCard>();
private Paint paint = new Paint();
public DroidCardsView(Context context) {
super(context);
initCards();
}
public DroidCardsView(Context context, AttributeSet attrs) {
super(context, attrs);
initCards();
}
/**
* 初始化卡片集合
*/
protected void initCards(){
Resources res = getResources();
mDroidCards.add(new DroidCard(res, R.drawable.alex,mCardLeft));
mCardLeft+=mCardSpacing;
mDroidCards.add(new DroidCard(res, R.drawable.claire,mCardLeft));
mCardLeft+=mCardSpacing;
mDroidCards.add(new DroidCard(res, R.drawable.kathryn,mCardLeft));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (DroidCard c : mDroidCards) {
drawDroidCard(canvas,c);
}
for (int i = 0; i < mDroidCards.size() - 1; i++){
drawDroidCard(canvas, mDroidCards,i);
}
drawLastDroidCard(canvas,mDroidCards.get(mDroidCards.size()-1));
invalidate();
}
private void drawDroidCard(Canvas canvas, DroidCard c) {
canvas.drawBitmap(c.bitmap,c.x,0f,paint);
}
/**
* 绘制最后一个DroidCard
* @param canvas
* @param c
*/
private void drawLastDroidCard(Canvas canvas,DroidCard c) {
canvas.drawBitmap(c.bitmap,c.x,0f,paint);
}
/**
* 绘制DroidCard
* @param canvas
* @param mDroidCards
* @param i
*/
private void drawDroidCard(Canvas canvas,List<DroidCard> mDroidCards,int i) {
DroidCard c = mDroidCards.get(i);
canvas.save();//备份画布
//裁剪画布
canvas.clipRect((float)c.x,0f,(float)(mDroidCards.get(i+1).x),(float)c.height);
canvas.drawBitmap(c.bitmap,c.x,0f,paint);
canvas.restore();//释放画布
}
}