性能優化06_佈局優化及Hierarchy Viewer使用

Android性能優化彙總
優化思想:查看自己的佈局,層次是否很深以及渲染比較耗時,然後想辦法能否減少層級以及優化每一個View的渲染時間。
CPU的優化,從減輕加工View對象成Polygons和Texture來下手

如何找出裏面沒用的view呢?或者減少不必要的view嵌套。
工具:Hierarchy Viewer檢測,通過View Hierarchy可以找到沒有用的view,這些view根本就不會顯示在屏幕上面,一旦觸發測量和佈局操作,就會拖累應用的性能表現。

一 Hierarchy Viewer使用

  1. 大開Android Monitor: 找不到工具的,Android Monitor路徑:打開sdk目錄下的tool文件夾中monitor.bat

  2. 切換到Hierarchy Viewer窗口
    在這裏插入圖片描述

  3. 選中要查看佈局的Activity,點擊load the view hierarchy into the tree view
    在這裏插入圖片描述

  4. view Tree 中能看到整個佈局視圖,包括PhoneWindow的

三個圓點分別代表:測量、佈局、繪製三個階段的性能表現。
1)綠色:渲染的管道階段,這個視圖的渲染速度快於至少一半的其他的視圖。
2)黃色:渲染速度比較慢的50%。
3)紅色:渲染速度非常慢。

  1. 問題:
  • Unable to get view server protocol version from device
    不顯示的話,關閉CPU顯示過度繪製,
  • Measure、LayoutDraw時間沒有,不顯示三個圓點
    開發者設置關閉、重新獲取刷新一下、選擇父控件、點擊右上角按鈕
    在這裏插入圖片描述

二 減少佈局嵌套

  • 主要減少Mesure、Layout
    方法: merge 和ViewStub、RelativeLayout減少佈局層級和加載

  • merge: 當我們的佈局是用的FrameLayout的時候,我們可以把它改成merge
    可以避免自己的幀佈局和系統的ContentFrameLayout幀佈局重疊造成重複計算(measure和layout)

  • ViewStub: 當加載的時候纔會佔用。不加載的時候就是隱藏的,僅僅佔用位置。
    例如: 一個ListView用wrapcontent,優化前的item如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/chat_padding_bottom">

    <ImageView
        android:id="@+id/chat_author_avatar"
        android:layout_width="@dimen/avatar_dimen"
        android:layout_height="@dimen/avatar_dimen"
        android:layout_margin="@dimen/avatar_layout_margin" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/darker_gray"
        android:orientation="vertical">

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#78A"
            android:background="@android:color/white"
            android:orientation="horizontal">

            <TextView xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:padding="@dimen/narrow_space"
                android:gravity="bottom"
                android:id="@+id/chat_author_name" />

            <TextView xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:textStyle="italic"
                android:padding="@dimen/narrow_space"
                android:id="@+id/chat_datetime" />
        </RelativeLayout>

        <TextView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="@dimen/narrow_space"
            android:background="@android:color/white"
            android:id="@+id/chat_text" />
    </LinearLayout>
</LinearLayout>

優化前Hierarchy顯示(有紅色、黃色警告)
在這裏插入圖片描述

ListView用MatchParent、Item使用RelativeLayout減少層級優化後

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/chat_author_avatar"
        android:layout_width="@dimen/avatar_dimen"
        android:layout_height="@dimen/avatar_dimen"
        android:src="@drawable/alex" />

    <TextView
        android:id="@+id/chat_author_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/chat_author_avatar"
        android:paddingLeft="@dimen/narrow_space"
        android:text="XXX" />

    <TextView
        android:id="@+id/chat_datetime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:paddingRight="@dimen/narrow_space"
        android:text="AAA"
        android:textStyle="italic" />

    <TextView
        android:id="@+id/chat_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/chat_datetime"
        android:layout_toRightOf="@id/chat_author_name"
        android:paddingBottom="@dimen/chat_padding_bottom"
        android:paddingLeft="@dimen/narrow_space"
        android:text="BBB" />

</RelativeLayout>

在這裏插入圖片描述
優化後,警告明顯減少了(ListView本身的測量和繪製還是比較耗時的)

三 減少過度繪製

工具: 設置-> 開發人員選項-> 調試GPU過度繪製
**查看:**局域顏色越深,過度繪製越嚴重(要排除控件本身背景色的干擾)

1 背景經常容易造成過度繪製。

解決的辦法: 將主題添加的背景去掉

 getWindow().setBackgroundDrawable(null);

2 自定義控件通過裁剪處理過度繪製。

優化前,在Canvas上重複繪製:

public class CardsView extends View {

    //圖片與圖片之間的間距
    private int mCardSpacing = 150;
    //圖片與左側距離的記錄
    private int mCardLeft = 10;

    private List<Card> mDroidCards = new ArrayList<>();

    private Paint paint = new Paint();

    public CardsView(Context context) {
        super(context);
        initCards();
    }

    public CardsView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initCards();
    }

    public CardsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initCards();
    }

    /**
     * 初始化卡片集合
     */
    protected void initCards() {
        Resources res = getResources();
        mDroidCards.add(new Card(res, R.drawable.alex, mCardLeft));

        mCardLeft += mCardSpacing;
        mDroidCards.add(new Card(res, R.drawable.claire, mCardLeft));

        mCardLeft += mCardSpacing;
        mDroidCards.add(new Card(res, R.drawable.kathryn, mCardLeft));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (Card c : mDroidCards) {
            drawCard(canvas, c);
        }
        invalidate();
    }

    private void drawCard(Canvas canvas, Card c) {
        canvas.drawBitmap(c.bitmap, c.x, 0f, paint);
    }


}

在這裏插入圖片描述
通過裁剪canvas優化,只繪製顯示的區域,注意canvas的恢復

public class OptimizationCardsView extends View {

    //圖片與圖片之間的間距
    private int mCardSpacing = 150;
    //圖片與左側距離的記錄
    private int mCardLeft = 10;

    private List<Card> mDroidCards = new ArrayList<>();

    private Paint paint = new Paint();

    public OptimizationCardsView(Context context) {
        super(context);
        initCards();
    }

    public OptimizationCardsView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initCards();
    }

    public OptimizationCardsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initCards();
    }

    /**
     * 初始化卡片集合
     */
    protected void initCards() {
        Resources res = getResources();
        mDroidCards.add(new Card(res, R.drawable.alex, mCardLeft));

        mCardLeft += mCardSpacing;
        mDroidCards.add(new Card(res, R.drawable.claire, mCardLeft));

        mCardLeft += mCardSpacing;
        mDroidCards.add(new Card(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();
    }

    /**
     * 繪製最後一個Card
     *
     * @param canvas
     * @param c
     */
    private void drawLastDroidCard(Canvas canvas, Card c) {
        canvas.drawBitmap(c.bitmap, c.x, 0f, paint);
    }

    /**
     * 繪製Card
     *
     * @param canvas
     * @param mDroidCards
     * @param i
     */
    private void drawDroidCard(Canvas canvas, List<Card> mDroidCards, int i) {
        Card c = mDroidCards.get(i);
        canvas.save();
        canvas.clipRect(c.x, 0f, mDroidCards.get(i + 1).x, c.height);
        canvas.drawBitmap(c.bitmap, c.x, 0f, paint);
        canvas.restore();
    }
}

在這裏插入圖片描述

發佈了231 篇原創文章 · 獲贊 75 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章