什麼是Overdraw?
Overdraw就是屏幕上某個像素點在同一幀被繪製了多次。在多層佈局結構中,不可見部分也會被繪製。舉個例子,一個白色頁面上有一個按鈕。系統首先繪製白色背景,然後在白色背景上繪製按鈕,最後在按鈕背景上繪製按鈕內容。那麼按鈕和按鈕內容就造成了Overdraw。
其實Overdraw是不可避免的,我們要做的是檢查Overdraw次數過多的地方,並刪掉無用的繪製。
如何檢查Overdraw?
在開發者工具中勾選Show GPU overdraw選項,觀察UI上的Overdraw情況。
該工具會以不同的顏色繪製在屏幕上,標識出該塊UI的Overdraw情況。
如果是透明色,表示只繪製了一次,沒有Overdraw。
我們要做的就是減少大面積的紅色區域,使其變成藍色甚至是透明色。對於深紅色,就要思考出了什麼問題,堅決進行優化。
優化菜鳥裹裹物流詳情頁面
首先打開Show GPU overdraw選項,觀察一下情況。
相當恐怖,幾乎全是深紅色。
分析Overdraw原因
佈局結構:基於ListView展示,快遞信息、物品信息、小件員信息在同一個View封裝,作爲HeaderView加入ListView,ListView的item展示物流跟蹤信息。
繪製層級:
第一層:window背景
第二層:Activity中fragment Container背景
第三層:Fragment中ListView背景
第四層:ListView的Header背景和物流信息item背景
第五層:快遞信息、物品信息、小件員信息背景和物流信息item內容
第六層+:快遞信息、物品信息、小件員信息內容
開始優化
第一步,刪除window默認背景
Android系統提供了默認的背景,被DecorView持有,但是通常情況,我們會爲全屏提供自定義顏色,那麼這個背景就沒用了,反而會帶來一次Overdraw的性能損耗。
Activity的onCreate方法中,調用getWindow().setBackgroundDrawable(null)即可刪除這個默認背景。
注意,這個方法應該在setContentView後調用。原因通過分析源碼可知:
setContentView通過調用PhoneWindow的setContentView,再到installDecor。最終通過以下代碼設置背景:
if (mDecor.getBackground() == null &&mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(mBackgroundFallbackResource);
}
- 1
- 2
- 3
- 1
- 2
- 3
而getWindow().setBackgroundDrawable(null)同樣會調用PhoneWindow的以下方法:
public final void setBackgroundDrawable(Drawable drawable) {
if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
mBackgroundResource = 0;
mBackgroundDrawable = drawable;
if (mDecor != null) {
mDecor.setWindowBackground(drawable);
}
if (mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
可以看出,如果先調用getWindow().setBackgroundDrawable(null), setContentView會再次設置背景色。
因此,getWindow().setBackgroundDrawable(null)應該在setContentView之後調用。
第二步,刪除佈局中重複設置的背景
整個佈局基於ListView全屏展示,因此和Activity中fragment container背景衝突,保留其中之一即可,在這裏選擇刪除ListView的背景,由container設置整體背景。
優化效果初見成效,滿屏的紅色沒有了,取而代之的是大塊的綠色和藍色,小塊淡紅色和極少的深紅色。
第三步,優化HeaderView
從UI設計來看,HeaderView的幾個區塊是白色背景,中間用灰色分割。
原來的實現方案是root view設置灰色背景,sub view使用margin暴露root view底色。如下圖:
這裏是存在優化空間的,可以將雙層結構改爲單層,區塊之間的分割使用灰色背景的view即可。修改後的結構如下圖:
通過佈局結構的優化,可以使HeaderView再減少一次Overdraw。
第四步,細粒度優化
觀察第二步優化後的情況,可以發現,物品信息TextView和快遞圖標ImageView還是存在深紅色。
檢查佈局文件發現,TextView設置了和parent view相同的背景色,這很簡單,刪除即可。
快遞圖標使用了兩個ImageView組成,一個展示快遞圖標,另一個爲圖標增加了邊框。我將兩個ImageView進行合併,通過src屬性展示圖標,background屬性設置邊框,並增加了1px的padding把邊框展示出來。
而物品圖標使用了自定義的ImageView,使用上述優化手段存在bug,暫不做處理。
至此,優化工作完成,下圖是優化後的效果。
可以看出,整屏基本上都是藍色,少量綠色以及小面積的淡紅色,基本達到了優化效果。
最後,總結一下優化步驟
- 刪除window默認背景。
- 刪除多層佈局結構中重複設置的背景
- 優化佈局,減少佈局層次。
- 檢查組件,刪繁去冗。