Android 性能優化之減小UI過分繪製

什麼是過分繪製(OverDraw)


在多層次重疊的UI結構裏面,若是不可見的UI也在作繪製的操做,會致使某些像素區域被繪製了屢次。這樣就會浪費大量的CPU以及GPU資源。過分繪製最直觀的影響就是會致使APP卡頓。還好系統有提供GPU過分繪製調試工具會在屏幕上用不一樣的顏色,來代表一個像素點位被重複繪製的次數。android

怎樣開啓GPU過分繪製調試工具?

1.點擊進入「設置」;
2.點擊進入「開發者選項」
3.選中「調試GPU過分繪製」
4.選中「顯示過分繪製區域」canvas

此時,你會注意到屏幕的顏色變化了,別緊張。切換到你的應用,如今咱們開始瞭解怎麼經過改善佈局來解決過分繪製問題。緩存

屏幕上不一樣的顏色表明着什麼?

1.原色沒有被過分繪製 – 這部分的像素點只在屏幕上繪製了一次。
2.藍色1次過分繪製– 這部分的像素點只在屏幕上繪製了兩次。
3.綠色2次過分繪製 – 這部分的像素點只在屏幕上繪製了三次。
4.粉色3次過分繪製 – 這部分的像素點只在屏幕上繪製了四次。
5.紅色4次過分繪製 – 這部分的像素點只在屏幕上繪製了五次。工具

怎麼解決應用過分繪製?

由上面的知識,咱們知道要解決過分繪製。便是要儘可能減小屏幕上的紅色區域,增長屏幕上的藍色和綠色區域。咱們的目標是要控制界面最多被過分繪製2次(不出現粉色和紅色)。佈局

1.合理選擇控件容器
既然overdraw是由於重複繪製了同一片區域的像素點,那咱們首先想到的是解決佈局問題。Android提供的Layout控件主要包括LinearLayout、TableLayout、FrameLayout、RelativeLayout(這裏咱們不考慮AbsoluteLayout)。同一個界面咱們可使用不一樣的容器控件來表達,可是各個容器控件描述界面的複雜度是不同的。通常來講LinearLayout最易,RelativeLayout較複雜。可是尺有所短,寸有所長,LinearLayout只能用來描述一個方向上連續排列的控件,容易致使佈局文件嵌套太深,不符合佈局扁平化的設計原理。而RelativeLayout幾乎能夠用於描述任意複雜度的界面。可是表達能力越強的容器控件,性能每每略低一些,由於RelativeLayout主要在onMeasure和onLayout階段會耗費更多時間。綜上所述:LinearLayout易用,效率高,表達能力有限。RelativeLayout複雜,表達能力強,可是效率稍遜。因此當某一界面在使用LinearLayout並不會比RelativeLayout帶來更多的控件數和控件層級時,咱們要優先考慮LinearLayout。可是要根據實際狀況來作一個取捨,在保證性能的同時儘可能避免OverDraw。性能


2.去掉window的默認背景
當咱們使用了Android自帶的一些主題時,window會被默認添加一個純色的背景,這個背景是被DecorView持有的。當咱們的自定義佈局時又添加了一張背景圖或者設置背景色,那麼DecorView的background此時對咱們來講是無用的,可是它會產生一次Overdraw,帶來繪製性能損耗。去掉window的背景能夠在onCreate()中setContentView()以後調用
getWindow().setBackgroundDrawable(null);優化

或者在theme中添加
android:windowbackground="null";ui


3.去掉其餘沒必要要的背景
有時候爲了方便會先給Layout設置一個總體的背景,再給子View設置背景,這裏也會形成重疊,若是子View寬度mach_parent,能夠看到徹底覆蓋了Layout的一部分,這裏就能夠經過分別設置背景來減小重繪。再好比若是採用的是selector的背景,將normal狀態的color設置爲「@android:color/transparent",也一樣能夠解決問題。這裏只簡單舉兩個例子,咱們在開發過程當中的一些習慣性思惟定式會帶來不經意的Overdraw,因此開發過程當中咱們爲某個View或者ViewGroup設置背景的時候,先思考下是否真的有必要,或者思考下這個背景能不能分段設置在子View上,而不是圖方便直接設置在根View上。spa


4.ClipRect & QuickReject
爲了解決Overdraw的問題,Android系統會經過避免繪製那些徹底不可見的組件來儘可能減小消耗。可是不幸的是,對於那些過於複雜的自定義的View(一般重寫了onDraw方法),Android系統沒法檢測在onDraw裏面具體會執行什麼操做,系統沒法監控並自動優化,也就沒法避免Overdraw了。可是咱們能夠經過canvas.clipRect()來幫助系統識別那些可見的區域。這個方法能夠指定一塊矩形區域,只有在這個區域內纔會被繪製,其餘的區域會被忽視。這個API能夠很好的幫助那些有多組重疊組件的自定義View來控制顯示的區域。同時clipRect方法還能夠幫助節約CPU與GPU資源,在clipRect區域以外的繪製指令都不會被執行,那些部份內容在矩形區域內的組件,仍然會獲得繪製。除了clipRect方法以外,咱們還可使用canvas.quickreject()來判斷是否沒和某個矩形相交,從而跳過那些非矩形區域內的繪製操做。
clip方法詳解設計


5.使用ViewStub佔位
ViewStub是個什麼東西?一句話總結:高效佔位符。咱們常常會遇到這樣的狀況,運行時動態根據條件來決定顯示哪一個View或佈局。經常使用的作法是把View都寫在上面,先把它們的可見性都設爲View.GONE,而後在代碼中動態的更改它的可見性。這樣的作法的優勢是邏輯簡單並且控制起來比較靈活。可是它的缺點就是,耗費資源。雖然把View的初始可見View.GONE可是在Inflate佈局的時候View仍然會被Inflate,也就是說仍然會建立對象,會被實例化,會被設置屬性。也就是說,會耗費內存等資源。推薦的作法是使用android.view.ViewStub,ViewStub是一個輕量級的View,它一個看不見的,不佔佈局位置,佔用資源很是小的控件。能夠爲ViewStub指定一個佈局,在Inflate佈局的時候,只有ViewStub會被初始化,而後當ViewStub被設置爲可見的時候,或是調用了ViewStub.inflate()的時候,ViewStub所向的佈局就會被Inflate和實例化,而後ViewStub的佈局屬性都會傳給它所指向的佈局。這樣,就可使用ViewStub來方便的在運行時,要仍是不要顯示某個佈局。

當你想加載佈局時,可使用下面其中一種方法:


6.用Merge減小布局深度
Merge標籤有什麼用呢?簡單粗暴點回答:幹掉一個view層級。Merge的做用很明顯,可是也有一些使用條件的限制。有兩種狀況下咱們可使用Merge標籤來作容器控件。第一種子視圖不須要指定任何針對父視圖的佈局屬性,就是說父容器僅僅是個容器,子視圖只須要直接添加到父視圖上用於顯示就行。另一種是假如須要在LinearLayout裏面嵌入一個佈局(或者視圖),而偏偏這個佈局(或者視圖)的根節點也是LinearLayout,這樣就多了一層沒有用的嵌套,無疑這樣只會拖慢程序速度。而這個時候若是咱們使用merge根標籤就能夠避免那樣的問題。另外Merge只能做爲XML佈局的根標籤使用,當Inflate以<merge />開頭的佈局文件時,必須指定一個父ViewGroup,而且必須設定attachToRoot爲true。
使用HierarchyViewer檢查佈局層級


7.善用draw9patch
給ImageView加一個邊框,你確定遇到過這種需求,一般在ImageView後面設置一張背景圖,露出邊框便完美解決問題,此時這個ImageView,設置了兩層drawable,底下一層僅僅是爲了做爲圖片的邊框而已。可是兩層drawable的重疊區域去繪製了兩次,致使overdraw。優化方案: 將背景drawable製做成draw9patch,而且將和前景重疊的部分設置爲透明。因爲Android的2D渲染器會優化draw9patch中的透明區域,從而優化了此次overdraw。 可是背景圖片必須製做成draw9patch才行,由於Android 2D渲染器只對draw9patch有這個優化,不然,一張普通的Png,就算你把中間的部分設置成透明,也不會減小此次overdraw。


8.慎用Alpha
假如對一個View作Alpha轉化,須要先將View繪製出來,而後作Alpha轉化,最後將轉換後的效果繪製在界面上。通俗點說,作Alpha轉化就須要對當前View繪製兩遍,可想而知,繪製效率會大打折扣,耗時會翻倍,因此Alpha仍是慎用。若是必定作Alpha轉化的話,能夠採用緩存的方式。

經過setLayerType方式能夠將當前界面緩存在GPU中,這樣不須要每次繪製原始界面,可是GPU內存是至關寶貴的,因此用完要立刻釋放掉。


9.避免「OverDesign」 overdraw會給APP帶來很差的體驗,overdraw產生的緣由無外乎:複雜的Layout層級,重疊的View,重疊的背景這幾種。開發人員無節制的View堆砌,究其根本無非是產品無節制的需求設計。有道是「由儉入奢易,由奢入儉難",不少APP披着過分設計的華麗外衣,卻忘了簡單易用纔是王道的本質,紛繁複雜的設計並不會給用戶帶來好的體驗,反而會讓用戶有壓迫感,產品自己也有可能所以變得卡頓。固然,一切拋開業務談優化都是空中樓閣,這就須要產品設計也要有一個權衡,在複雜的業務邏輯與簡單易用的界面展示中作一個平衡,而不是一味的OverDesign。

做者:Rave_Tian 連接:https://www.jianshu.com/p/2cc6d5842986 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
相關文章
相關標籤/搜索