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>