Android性能優化(二)佈局渲染流程優化

佈局渲染流程優化

一、CPU與GPU繪製原理

CPU 的任務繁多,做邏輯計算外,還要做內存管理、顯示操作,因此 在實際運算的時候性能會大打折扣,在沒有 GPU 的時代,不能顯示覆 雜的圖形,其運算速度遠跟不上今天覆雜三維遊戲的要求。即使 CPU 的工作頻率超過 2GHz 或更高,對它繪製圖形提高也不大。這時 GPU 的設計就出來了。

CPU 的控制器較爲複雜,而 ALU 數量較少。因此 CPU 擅長各種複雜 的邏輯運算,但不擅長數學尤其是浮點運算。

二、卡頓原理分析

1、當一幀的畫面渲染超過16ms的時候,我們就會感覺到卡頓。

首先我們要先明確,我們的手機頻率爲60FPS,意思爲我們的手機會在1秒內刷新60次,也就是約16ms刷新一次。
Android 系統每隔 16ms 發出 VSYNC 信號 (1000ms/60=16.66ms) ,觸發對 UI 進行渲染, 如果每次渲染都成 功這樣就能夠達到流暢的畫面所需要的 60fps ,爲了能夠實現 60fps ,這意味着計算渲染的大多數操作都必須 在 16ms 內完成。
這就彷彿我們的手機會16ms發送一趟列車,如果你沒有坐上只能等下一趟。
如果錯過了,比如說我們花費34ms才完成計算,那麼就會出現我們稱之爲丟幀的情況。

2、16 毫秒的時間主要被兩件事情所佔用 :

第一件:CPU將UI對象轉換爲一系列多邊形和紋理
第二件:CPU傳遞處理數據到GPU。所以很明顯,我們要縮短這兩部分的時間,也就是說需要儘量減少對象轉換的次數,以及上傳數據的次數。

3、得出初步解決思路
CPU減少xml轉化成對象的時間
GPU減少重複繪製的時間

三、什麼是過度繪製

GPU的繪製過程,就跟刷牆一樣,一層層的進行,16ms刷一次,這樣就會造成塗層覆蓋的現象,即無用的圖層還被繪製在底層,造成不必要的浪費。

1、GPU過度繪製的幾種情況:
1)、自定義控件中 onDraw 方法做了過多的重複繪製
2)、佈局層次太深,重疊性太強。用戶看不到的區域GPU也會渲染,導致耗時增加。

2、過度繪製查看工具
在手機端的開發者選項裏,有overDraw監測工具,調試GPU過度繪製工具,其中顏色代表圖層渲染情況。

藍色:過度繪製一次,無過度繪製;
淡綠:過度繪製兩次;
淡紅:過度繪製三次;
深紅:過度繪製四次;

代表4種不同程度overDraw情況,我們的目的就是儘量減少紅色,看到更多的藍色區域。

四、Android系統所做的優化

CPU 轉移到 GPU 是一件很麻煩的事情,所幸的是 OpenGL ES 可以把那些需要渲染的紋理 Hold 在 GPU Memory 裏面,在下次需要渲染的時候直接進行操作。所以如果你更新了 GPU 所 hold 住的紋理內容,那麼之前保存的狀態就丟失了。
在 Android 裏面那些由主題所提供的資源,例如 Bitmaps ,Drawables 都是一起打包到統一的 Texture 紋理當中,然後再傳 遞到 GPU 裏面,這意味着每次你需要使用這些資源的時候,都是直接從紋理裏面進行獲取渲染的。當然隨着 UI 組件的越來 越豐富,有了更多演變的形態。例如顯示圖片的時候,需要先經過 CPU 的計算加載到內存中,然後傳遞給 GPU 進行渲染。 文字的顯示比較複雜,需要先經過 CPU 換算成紋理,然後交給 GPU 進行渲染,返回到 CPU 繪製單個字符的時候,再重新 引用經過 GPU 渲染的內容。動畫則存在一個更加複雜的操作流程。
爲了能夠使得 App 流暢,我們需要在每幀 16ms 以內處理完所有的 CPU 與 GPU 的計算,繪製,渲染等等操作。

五、App層如何優化GPU過度繪製

1,去掉默認背景
1>. 如果在佈局的Layout中設置background,禁用主題的背景可以少繪製一層。
2>. 在Activity上嵌套的Fragment如果背景與Activity一致也可以去掉背景。
3>. 檢查每一個容器與內部的item與外層是否有重複使用的顏色部分,也可以去掉每一個容器與item的背景
2、如果是自定義view,可以去掉不用展示的部分
繪製的圖片如果有重疊的部分,就像撲克牌一樣,有被蓋住的部分,我們可以通過截取畫板的形式,只繪製該圖片顯示區域的大小。
可使用canvas.clipRect()方法
比如:

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 (int i = 0; i < mDroidCards.size() - 1; i++){
            drawDroidCard(canvas, mDroidCards,i);
        }

        drawLastDroidCard(canvas,mDroidCards.get(mDroidCards.size()-1));
        invalidate();
    }

    /**
     * 繪製最後一個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();
    }
}

六、App層如何優化CPU紋理化:減少嵌套

1、佈局優化工具:Hierarchy view
在Android Studio中打開 tool ==》Hierarchy view進行調試。
Hierarchy view的所顯示的樹狀圖DecorView分爲三部分:statusBarnavigationBar,還有一個填充着我們佈局的LinerLayout
所以我們能優化的部分只有總的填充我們佈局的LinerLayout部分。
2、優化思路
1>. 用merge標籤替換FrameLayout,避免與父容器重疊。
2>. 如果在Hierarchy view的所顯示的樹狀圖中某一個layout後面只有一個分支,那麼它就可以被幹掉,減少一層嵌套。
3>. 儘量減少LinerLayoutRelativeLayout等與之同級別大layout之間的互相嵌套。
4>. 在大容器內儘量只嵌套類似於TextView這種的子佈局

七、性能優化主要思想

性能優化其實不僅僅是一種技術,而是一種思想,它其實就是各個細節處的深入研究和處理,和擠牙膏一樣。優化時主要有以下思路:
1、佈局內是否有背景。

2、是否可以刪除多個佈局。(儘量容器內只有一個子節點)(適時使用ScroView代替linerLayout)。
3、自定義View是否進行了裁剪(適時使用include加載多次重繪的子佈局)。
4、在Hierarchy view的所顯示的樹狀圖上觀察佈局是否扁平化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章