佈局渲染筆記

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>
相關文章
相關標籤/搜索