CPU 处理逻辑计算和内存管理,显示操做。java
GPU CPU没法显示复杂的图形,GPU用于显示复杂图形,分担CPU的任务android
xml布局到屏幕的显示流程:xml 经过 LayoutInflater 加载到内存中,而后通过CPU计算处理为多维图形,在经过 OpenGL 调用GPU,GPU对图形进行栅格化显示到屏幕上,此时若是上面流程在16毫秒内完成,则直接显示到显示器,若是没能完成,则垂直同步等待下一帧完成。canvas
因为人类的眼睛看到画面之帧率高于每秒约10-12帧的时候,就会认为是连贯的;app
对于有声电影的拍摄和播放帧率均为每秒24帧,对人是能够接受的,可是早期的高动态电子游戏帧率若是少于每秒30帧的话就会不连贯,由于没有动态模糊使流畅度下降,在于手机交互的过程当中,若是触摸反馈60帧如下人是能够感受出来的,60帧以上不能察觉变化,当手机上帧率低于60fps的时候会感受画面的卡顿和迟滞现象;ide
Android系统每隔16ms发出信号,触发对UI进行渲染,若是每次渲染都成功,就能达到流程的画面所须要的60fps,为了可以实现60fps,这意味着计算渲染的太多数操做都必须在16ms内完成。布局
当一帧画面渲染时间超过16ms的时候,垂直同步机制(每隔16ms刷新帧率)会让显示器硬件等待GPU完成栅格化渲染操做,这样会让一帧画面多停留16ms甚至更多,这样就形成了用户看起来画面停顿。优化
优化:this
CPU 减小xml转换成对象的时间,好比减小层级spa
GPU 减小重复绘制调试
GPU的绘制过程根据CPU传递的指令来绘制,16ms绘制一次,指令来了就绘制,哪怕是一样的绘制指令,若是层次太深,用户看不到的区域也会被绘制,以及自定义控件中,onDraw方法作了过多的绘制。
Android手机开发者选项中,打开GPU过分绘制调试,蓝色 表示绘制了一次,淡绿色表示两次,淡红色表示三次,深红色表示四次。
注意:Android的Theme-主题中,是自带背景的,能够设置windowBackground为null
下面是一个过分绘制的例子,注释部分为过分绘制,打开部分为优化后的绘制,打开GPU调试后运行查看过分绘制区域,做比较
import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; import java.util.ArrayList; import java.util.List; import androidx.annotation.Nullable; public class DroidCardsView extends View { private int mCardSpacing = 150;//图片间隔 private int mCardLeft = 50;//图片左侧距离 private List<DroidCard> mDroidCards = new ArrayList<>(); private Paint paint = new Paint(); public DroidCardsView(Context context) { super(context); initCards(); } public DroidCardsView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initCards(); } private void initCards(){ Resources res = getResources(); mDroidCards.add(new DroidCard(res,R.mipmap.testpic1,mCardLeft)); mCardLeft += mCardSpacing; mDroidCards.add(new DroidCard(res,R.mipmap.testpic2,mCardLeft)); mCardLeft += mCardSpacing; mDroidCards.add(new DroidCard(res,R.mipmap.testpic1,mCardLeft)); mCardLeft += mCardSpacing; mDroidCards.add(new DroidCard(res,R.mipmap.testpic2,mCardLeft)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // for (DroidCard card : mDroidCards) { // drawDroidCard(canvas,card); // } // invalidate(); for (int i = 0;i < mDroidCards.size() -1;i++) {//最后一张不裁剪 drawDroidCard(canvas,mDroidCards,i); } drawLeftDroidCard(canvas,mDroidCards.get(mDroidCards.size() -1)); invalidate(); } private void drawDroidCard(Canvas canvas,DroidCard card){ canvas.drawBitmap(card.bitmap,card.left,0f,paint); } private void drawLeftDroidCard(Canvas canvas,DroidCard card){ canvas.drawBitmap(card.bitmap,card.left,0f,paint); } private void drawDroidCard(Canvas canvas,List<DroidCard> list,int i){ DroidCard card = list.get(i); /*Canvas中当前路径不属于保存状态,状态包含线条,平移,颜色,渐变,阴影等*/ canvas.save();//保存画布状态,第二次绘制在起点,由于这里每个的x坐标是以左侧为起点累加的 //获取当前图片的 left 值,裁剪出当前图片显示的区域,而且绘制 canvas.clipRect(card.left,0f,list.get(i+1).left,card.height); canvas.drawBitmap(card.bitmap,card.left,0f,paint); canvas.restore(); } }
import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class DroidCard { public Bitmap bitmap; public int left,width,height; public DroidCard(Resources resources,int resId,int left){ this.bitmap = BitmapFactory.decodeResource(resources,resId); this.left = left; this.width = bitmap.getWidth(); this.height = bitmap.getHeight(); } }
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.example.testdemo.DroidCardsView android:layout_width="match_parent" android:layout_height="150dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> </RelativeLayout>