AndrodUI優化之佈局優化

前些天在 那些年大家都在談論的Android性能優化 中已經跟大家分享了Android中性能優化的概念,優化的一些關鍵點以及優化方案。今天跟大家探討一下AndroidUI優化中的佈局優化具體是怎麼操作的。

選擇合適的ViewGroup

1.FrameLayout和LinearLayout是Android中比較簡單並且高效的viewgroup,如果不考慮佈局嵌套的話,儘量使用這兩種。
2.大多數情況單純使用FrameLayout或者LinearLayout無法實現產品效果,需要進行佈局嵌套,這種情況儘量使用RelativeLayout。嵌套會增加布局的層級,降低App的性能。大約在Android4.0之後,新建工程的默認main.xml中頂節點改成了RelativeLayout,因爲RelativeLayout性能更優,可以簡單實現LinearLayout嵌套才能實現的佈局。

抽象佈局標籤

include

include主要用於佈局重用,將佈局中的公共部分抽離出來供其他佈局用,實現佈局的模塊化,比如App的頂欄等。

<?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="vertical">

    <include
        android:id="@+id/title"
        layout="@layout/layout_title" />

    <android.support.v4.view.ViewPager
        android:id="@+id/fragment_home_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

include標籤唯一需要的屬性是layout屬性,指定需要包含的佈局文件。可以定義android:id和android:layout_*屬性來覆蓋被引入佈局根節點的對應屬性值。注意重新定義android:id後,子佈局的頂結點id就變化了。如果被指定了android:layout_*屬性,那麼android:layout_width和android:layout_height也必須存在,否則其他android:layout_*屬性不生效。

merge

merge標籤一般和include標籤一起使用,可以減少佈局的層級。假如我的layout_title文件中的根節點也是豎直方向的linearlayout,我們可以通過merge標籤來減少這一層linearlayout。

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <Button
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/menu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</merge>

另一種情況是當佈局頂結點是FrameLayout且不需要設置background或padding等屬性,可以用merge代替,因爲Activity內容視圖的parent view就是個FrameLayout,所以可以用merge消除只剩一個。

viewstub

viewstub引入的佈局默認不會擴張,即既不會佔用顯示也不會佔用位置,不參與任何的佈局和繪製過程,從而在解析layout時節省cpu和內存。它的意義在於按需加載佈局文件,比如網絡異常的界面正常情況下是不會顯示的,我們就沒有必要在初始化的時候就把它加載進來。

<?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="vertical">

    <include
        android:id="@+id/title"
        layout="@layout/layout_title" />

    <android.support.v4.view.ViewPager
        android:id="@+id/fragment_home_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <ViewStub
        android:id="@+id/network_error_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/network_error" />
</LinearLayout>

network_error的內容

<?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" >

    <Button
        android:id="@+id/network_setting"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="@string/network_setting" />

    <Button
        android:id="@+id/network_refresh"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/network_setting"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/dp_10"
        android:text="@string/network_refresh" />

</RelativeLayout>

如果要顯示viewstub中的內容,可以通過setVisibility或者inflate進行加載。

private View networkErrorView;

private void showNetError() {
    //保證不重複加載
    if (networkErrorView != null) {
        networkErrorView.setVisibility(View.VISIBLE);
        return;
    }

    ViewStub stub = (ViewStub)findViewById(R.id.network_error_layout);
    networkErrorView = stub.inflate();
    Button networkSetting = (Button)networkErrorView.findViewById(R.id.network_setting);
    Button refresh = (Button)findViewById(R.id.network_refresh);
}

private void showNormal() {
    if (networkErrorView != null) {
        networkErrorView.setVisibility(View.GONE);
    }
}

減少不必要的infalte

1.對於inflate的佈局可以直接緩存,用全部變量代替局部變量,避免下次需再次inflate
2.ListView提供了item緩存,adapter getView的標準寫法,如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.list_item, null);
        holder = new ViewHolder();
        ……
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }
}

/**
 * ViewHolder
 * 
 * @author [email protected] 2013-08-01
 */
private static class ViewHolder {

    ImageView appIcon;
    TextView  appName;
    TextView  appInfo;
}

決定偉大水平和一般水平的關鍵因素,既不是天賦,也不是經驗,而是刻意練習的程度。從下一頁面開始,希望大家都能按照這些標準去寫,刻意練習,熟能生巧。

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