一、頁面佈局對App性能的影響和原因
佈局性能主要影響 :App的頁面顯示速度。
佈局影響性能的實質:頁面的測量 & 繪製時間,一個頁面通過遞歸完成測量 & 繪製過程。
二、優化思路
合理的佈局性能、佈局層級、佈局複用性 和 按需加載(測量&繪製時間)。
在佈局優化中,Android的官方提到了這三種標籤、、,下面也是簡單說一下它們的優勢,以及怎麼使用。
三、具體方案
(一) 提高佈局的複用性
1、作用:提取佈局間的公共部分,通過提高佈局的複用性從而減少測量 & 繪製時間。
2、使用:
<include layout="@layout/titlebar"/>
<TextView
android:layout_width=”match_parent”
android:layout_height="wrap_content"
android:text="@string/Hello World"
android:padding="10dp" />
3、特別注意:
(1)include標籤可以使用單獨的layout屬性,這個也是必須使用的。
(2)include標籤若指定了id屬性,而layout也定義了id,則layout的id會被覆蓋。
(二) 減少視圖層級
1、作用:減少佈局層級,配合include標籤使用,可優化加載佈局文件時的資源消耗。
2、使用:
merge標籤在UI的結構優化中起着非常重要的作用,它可以刪減多餘的層級,優化UI。merge多用於替換FrameLayout或者當一個佈局包含另一個時,merge標籤消除視圖層次結構中多餘的視圖組。
例如:你的主佈局文件是相對佈局,引入了一個相對佈局的include,這時include佈局使用的RelativeLayout就沒意義了,反而減慢UI渲染。這時可以使用merge標籤優化。
//佈局A:layout_a.xml
<?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/button"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_10"/>
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_heig
ht="@dimen/dp_10"/>
//佈局B:layout_b.xml
<?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/Button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/dp_10" />
<include layout="@layout/layout_a.xml" />
</RelativeLayout>
複製代碼在上述例子,在佈局B中通過標籤引用佈局A,
此時B佈局層級爲 = RelativeLayout ->> Button
—>> RelativeLayout
->> Button
->> TextView
複製代碼現在使用merge優化,將被引用佈局A根標籤的RelativeLayout改爲merge。那麼在引用佈局A時,佈局A中的merge標籤內容根節點RelativeLayout會被去掉,在include標籤裏存放的是佈局A中的merge標籤爲根節點的子節點即include裏存放的是:Buttton和TextView
此時B佈局層級爲 = RelativeLayout ->> Button
->> Button
->> TextView
複製代碼即已去掉之前無意義且多餘的,
//佈局A:layout_a.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_10"/>
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_10"/>
</merge>
(三) 按需加載
1、作用:按需加載 外部引入的佈局,注:屬輕量級View、不佔用顯示 & 位置。
標籤最大的優點是當你需要時纔會加載,使用它並不會影響UI初始化時的性能。各種不常用的佈局想進度條、顯示錯誤消息等可以使用標籤,以減少內存使用量,加快渲染速度。是一個不可見的,大小爲0的View。
2、使用:
// 步驟1、先設置好預顯示的佈局
// 步驟2、在其他佈局通過<ViewStub>標籤引入外部佈局(類似<include>)
注:此時該佈局還未被加載顯示。
// 步驟3、只有當ViewStub被設置爲可見ViewStub.setVisibility(View.VISIBLE)或者
調用ViewStub.inflate()時,ViewStub所指向的佈局文件纔會被inflate、
實例化,最終 顯示<ViewStub>指向的佈局。
/**
* 實例說明:在佈局A中引入佈局B,只有在特定時刻C中才顯示
*/
// 步驟1:先設置好預顯示的佈局B = layout_b.xml
<?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/button"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_10"/>
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_10"/>
</RelativeLayout>
// 步驟2:在佈局A通過<ViewStub>標籤引入佈局B(類似<include>);注:此時該佈局還未被加載顯示
// 佈局A:layout_a.xml
<?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/Button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/dp_10" />
<ViewStub
android:id="@+id/Blayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/layout_b" />
</RelativeLayout>
// 步驟3:
只有當ViewStub被設置爲可見 / 調用了ViewStub.inflate()時,ViewStub所指向的佈局文件
纔會被inflate 、實例化,最終 顯示<ViewStub>指向的佈局
ViewStub stub = (ViewStub) findViewById(R.id.Blayout);
stub.setVisibility(View.VISIBLE);
//or
stub.inflate();
3、特別注意:
(1) ViewStub中的layout佈局不能使用merge標籤,否則會報錯。
(2)ViewStub的inflate只能執行一次,顯示了之後,就不能再使用ViewStub控制它了。
(3)與View.setVisible(View.Gone)的區別:
共同點:初始時不會顯示
不同點:ViewStub標籤只會在顯示時,纔會渲染整個佈局。View.GONE在初始化佈局樹的時候就已經添加在佈局樹上了。相比之下ViewStub標籤節省佈局文件的解析時間和內存的佔用,從而具有更高的效率。
(四) 選擇耗費性能較少的佈局
1、性能耗費低的佈局 = 功能簡單 = LinearLayout、FrameLayout
2、性能耗費高的佈局 = 功能複雜 = RelativeLayout,即佈局過程需消耗更多性能(CPU資源 & 時間)
3、嵌套多個佈局所耗費的性能 > 單個佈局本身耗費的性能,即完成需求時:寧選擇單個耗費性能高的佈局,也不採用嵌套多個耗費性能低的佈局。
4、通過合理選擇佈局類型,從而減少嵌套。即:完成複雜的UI效果時,儘可能選擇1個功能複雜的佈局(如RelativeLayout)完成,而不要選擇多個功能簡單的佈局(如LinerLayout)通過嵌套完成。