布局優(yōu)化措施大綱:
-
過度繪制
Overdraw(過度繪制):描述的是屏幕上的某個像素在同一幀的時間內(nèi)被繪制了多次。在多層次的UI結(jié)構(gòu)里面,如果不可見的UI也在做繪制的操作,就會導(dǎo)致某些像素區(qū)域被繪制了多次,浪費(fèi)大量的CPU以及GPU資源,因?yàn)榈紫卤桓采w區(qū)域怎么重繪也沒有意義。當(dāng)view內(nèi)容發(fā)生改變時,整個view都會重繪,如果層次太“豐富”,那性能就會嚴(yán)重下降。
過渡繪制層次:
無色: 意味著沒有overdraw。像素只畫了一次。
藍(lán)色: 意味著overdraw 1倍。像素繪制了兩次。大片的藍(lán)色還是可以接受的(若整個窗口是藍(lán)色的,可以擺脫一層)。
綠色: 意味著overdraw 2倍。像素繪制了三次。中等大小的綠色區(qū)域是可以接受的但你應(yīng)該嘗試優(yōu)化、減少它們。
淺紅: 意味著overdraw 3倍。像素繪制了四次,小范圍可以接受。
暗紅: 意味著overdraw 4倍。像素繪制了五次或者更多。這是錯誤的,要修復(fù)它們。
界面繪制層次顏色圖:
-
合理選擇容器
LinearLayout易用,效率高,表達(dá)能力有限。RelativeLayout復(fù)雜,表達(dá)能力強(qiáng),效率稍遜,但是relativeLayout可以減少布局層級,用一層寫出復(fù)雜的嵌套。ConstraintLayout可以更好地減少層級,平鋪布局層級。
Viewstub 高效占位符
我們經(jīng)常會遇到這樣的情況,運(yùn)行時動態(tài)根據(jù)條件來決定顯示哪個View或布局。常用的做法是把View都寫在上面,先把它們的可見性都設(shè)為View.GONE,然后在代碼中動態(tài)的更改它的可見性。這樣的做法的優(yōu)點(diǎn)是邏輯簡單而且控制起來比較靈活。但是它的缺點(diǎn)就是,耗費(fèi)資源。雖然把View的初始可見View.GONE但是在Inflate布局的時候View仍然會被Inflate,也就是說仍然會創(chuàng)建對象,會被實(shí)例化,會被設(shè)置屬性。也就是說,會耗費(fèi)內(nèi)存等資源。
ViewStub是一個輕量級的View,它一個看不見的,默認(rèn)不占布局位置,在Inflate布局的時候,只有ViewStub會被初始化。在要顯示的時候調(diào)用 ((ViewStub)findViewById(R.id.stub_view)).setVisibility(View.VISIBLE);讓其可見,ViewStub內(nèi)部的布局就會被Inflate和實(shí)例化。
viewstub常用來引入那些默認(rèn)不會顯示,只在特殊情況下顯示的布局,如進(jìn)度布局、網(wǎng)絡(luò)失敗顯示的刷新布局、信息出錯出現(xiàn)的提示布局等。
Merge
當(dāng)布局根布局沒有實(shí)際屬性僅僅起的是一個簡單的父viewgroup時,可以用merge來代替,merge不會作為一個層級進(jìn)行繪制。3434s
-
業(yè)務(wù)邏輯簡化
在設(shè)計(jì)業(yè)務(wù)邏輯時,盡量不要過度設(shè)計(jì)。華麗的App界面畢竟會犧牲繪制性能。在功能完成的前提下,盡量設(shè)計(jì)層級簡單操作簡單。
-
優(yōu)化工具
Lint工具檢測布局層次
lint檢測工具開啟2項(xiàng)布局性能的檢測指標(biāo),如果有布局嵌套層次深的,會檢測報出問題。
點(diǎn)擊Code菜單的Inspect Code觸發(fā)Lint檢測。
Layout Inspector
在Tools -> Layout Inspector,選擇對應(yīng)相應(yīng)進(jìn)程,打開界面層級檢查
可根據(jù)view類型和對應(yīng)id選擇查看,可切換2D、3D功能進(jìn)行查看。
布局加載優(yōu)化
xmlPullParser IO操作,布局越復(fù)雜,IO耗時越長。
createView 反射,View越多,反射調(diào)用次數(shù)越多,耗時越長,但是這必須達(dá)到一定量級才會有明顯影響。
直接解決就是不使用IO和反射技術(shù),我們這里介紹側(cè)面緩解,即將布局加載和解析放在子線程中,等到inflate操作完成后再將結(jié)果回調(diào)到主線程中,即使用Android為我們提供的AsyncLayoutInflater類來進(jìn)行異步布局加載。
AsyncLayoutInflater
AsyncLayoutInflater是google提供的方案,讓LayoutInflater.inflater過程通過子線程來做:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new AsyncLayoutInflater(this).inflate(R.layout.activity_main,null, new AsyncLayoutInflater.OnInflateFinishedListener(){
@Override
public void onInflateFinished(View view, int resid, ViewGroup parent) {
setContentView(view);
rv = findViewById(R.id.tv);
rv.setLayoutManager(new V7LinearLayoutManager(MainActivity.this));
rv.setAdapter(new RightRvAdapter(MainActivity.this));
}
});
}
布局繪制監(jiān)控
獲取布局文件加載耗時的方法
val start = System.currentTimeMillis()
setContentView(R.layout.activity_layout_optimize)
val inflateTime = System.currentTimeMillis() - start
這種方法很簡單,因?yàn)閟etContentView是同步方法,如果想要計(jì)算耗時,直接將前后時間計(jì)算相減即可得到結(jié)果了
優(yōu)化布局層級及復(fù)雜度
1.使用ConstraintLayout,可以實(shí)現(xiàn)完全扁平化的布局,減少層級
2.RelativeLayout本身盡量不要嵌套使用
3.嵌套的LinearLayout中,盡量不要使用weight,因?yàn)閣eight會重新測量兩次
4.推薦使用merge標(biāo)簽,可以減少一個層級
5.使用ViewStub延遲加載
避免過度繪制
1.去掉多余背景色,減少復(fù)雜shape的使用
2.避免層級疊加
3.自定義View使用clipRect屏蔽被遮蓋View繪制
參考:
http://www.lxweimin.com/p/9e8f88eac490
https://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650271556&idx=1&sn=f9c444f67322deb2a818ae2fca3f0e52#rd