【轉】Android性能優化之GPU過度繪制與圖形渲染優化


 

Android之GPU過度繪制與圖形渲染優化

寫在前面的話

本文主要對過度繪制和圖形渲染做一個概念性的描述,和簡單的優化措施。 
如果你已對過度繪制有過一些了解,那么你應該明白,僅是簡單的層級優化對過度繪制的改善是很小的。所以,這時候你可以參考這篇文章:

另外如果你還想知道更多關於View優化原理,可以參考這篇文章: 
http://www.oschina.net/news/60157/android-performance-patterns

1. 概念



GPU過度繪制:

      是指在一個像素點上繪制多次(超過一次)。舉一個簡單的例子:顯示一個什么都沒有做的activity界面算作畫了1層,給activity加一個背景是第2層,在上面放了一個Text View(有背景的Text View)是第3層,Text View顯示文本就是第4層 。

      僅僅只是為了顯示一個文本,卻在同一個像素點繪制了四次,這是一定要優化的!

      還有,過度繪制對動畫性能的影響是極其嚴重的。如果你想要流暢的動畫效果,那么一定不能忽視過度繪制!!

圖形渲染優化:

      一個View的繪制過程:測量、布局、畫圖。三者的累積時間,就是一個View的最終繪制時間 。 過多的層級、無用的子節點父節點、過於依賴系統計算位置的布局屬性(如: weight)。都會引起上述三個過程時間的增加。

2.關鍵點/字

 

  • 過渡繪制優化與圖形渲染優化都其目的都是為了提供一個高效的UI。其目的相似,優化方式也有相同之處,所以一起進行總結。

  • 調試GPU過渡繪制顏色區域說明

    無/白色:繪制1次
    藍色:繪制2次(理想狀態)
    綠色:繪制3次
    淺紅:繪制4次(要優化了)
    深紅:繪制5次或5次以上。(必須要優化了)

圖片名稱

  • 調試Hierarchy Viewer 顏色說明

    下方三個原點從左到右:測量、布局、畫圖時間
    紅色:該View所用時間超過大部分View很多
    黃色:該View所用時間超過大部分View
    綠色:該View所用時間低於大部分View

    這里寫圖片描述

  • 引起過度繪制的兩個主要因素:層級與背景圖片

    - 層級為透明時(不添加背景),不會引起過度繪制,但會引起測量、布局、畫圖時間的顯著提高。
    - 改變View形狀,也算是繪制一層。添加一個橢圓形的黑色背景,算作兩層
    - 值得注意的是,背景圖片的繪制是及其耗時的
  • 一個通常的錯誤觀念就是使用基本的布局結構(例如:LinearLayout、FrameLayout等)能夠在大多數情況下產生高效率的布局。

    基本的線性布局會導致過於累贅的層級嵌套結構。使用相對布局優化。
    但並不是所有情況下都應該用相對布局。(相對布局過於復雜,且通讀性差)應考慮權衡關系。

3.優化措施

  • 在Theme中給activity增加背景。使用WindowBackground屬性。

    背景的繪制是非常耗時的,在Theme中添加背景,不算繪制一層,並且View渲染時間減少很多。
    具體原因詳解請參考:
  • 減少層級,沒必要的背景圖

    (如果一個View和它所在的Layout的顏色相同,就不需要給兩個都設置背景)
  • 避免使布局太深,而應該讓布局更淺更深

    (用相對布局替換線性布局)
  • 無用的子節點、父節點刪除

    沒有免費的午餐,性能優化最重要的一點便是:不要做多余的事情。舉例:
    1.想要設置控件之間的間距,使用 layout_marginTop 之類的屬性,
    而不是填充一個透明的TextView
    2.如果你需要的效果僅是一張圖片加一串文字。那么不需要使用兩個控件:TextView+ImageView.  
    TextView一個控件足以。
  • 對於要被的布局,如果沒有背景或Padding,使用 merge 標簽作為根布局

  • 避免出現多個使用layout-weight屬性的的LinearLayout。

    首先我們必須要承認layout-weight的靈活性,但在使用時,請再三考慮是否真的有必要。
    weight將導致大量的系統開銷,每個子項目都要測量兩次。
  • 合並作為根節點的幀布局(Framelayout)

    你需要知道的一個知識點:Activity或Fragment的默認根布局是FrameLayout。
    如果一個幀布局時布局文件中的根節點,而且它沒有背景圖片或者padding等。
    更有效的方式是使用<merge />標簽替換該< Framelayout />標簽 。
  • 使用組合控件

    首先說明的是,組合控件並不會減少過度繪制,也不會減少View的繪制時間。
    但它會讓你的布局文件看起來非常的清晰。
    並且對於一些條狀的控件。類似與下圖這樣的控件。
    當你需要給這樣的控件添加點擊事件時,你可能需要給一個layout,兩個TextView都添加。
    使用組合控件包裝你的view,既符合封裝的特性,又可以減少代碼量

重要的東西放到最后說:

  • 重繪控件,提前繪制控件背景與形狀,使得View在放到界面上之前就已經畫好。極為有效的避免過度繪制。

    說實話,直接使用原生控件很難避免過度繪制:
    一個Button,繼承與TextView,所以直接就已經被繪制了兩次(TextView一次,加Button背景第二次)
    那么這是你需要終極絕招:View提前繪制。
    不過需要你抉擇的是,提前繪制是一項復雜的工作,所以在復雜布局中使用OK,過於簡單的布局就沒有必要了。
    樓主正在努力將提前繪制控件類庫化,但目前較為遺憾的是,很難抽取提前繪制控件的相同點。
    不同需求畫法是不一樣的。

4. 案例說明 – 登錄界面

      為了簡化解說,我們使用登錄界面作為案例。但對於 控件的提前繪制來說,在登錄界面投入和產出並不等比,控件提前繪制,你應該關注復雜的界面,尤其是這復雜的界面上還有動畫效果。

開啟過度繪制檢測后 ,上邊是我們未經優化的界面。下邊是QQ空間的登錄界面。

圖片名稱

圖片名稱

驚訝嗎?沒關系,我們也可以做到。

之后再看我們的UI層級圖:

這里寫圖片描述

下面我們一步步分析優化。

優化1:

      優化布局結構,解決過深的UI層級圖,與無用的子節點

  • 過深的LinearLayout嵌套LinearLayout 嵌套LinearLayout 。並且通讀性較差

這里寫圖片描述

優化方案1:采用相對布局,使得布局變淺變寬。最大可以保證只有兩層。

優化方案2:觀察可以得知,布局整體大方向為垂直線性,采用組合控件(帶小圖標的輸入框作為一個整體控件)加垂直線性布局。

  • 無用的子節點。

這里寫圖片描述

一個布局里只放了一個Button按鈕,次布局為無用的子節點,去掉。

優化2

      子view過久的測量時間。

這里寫圖片描述

查看其代碼:

<com.envision.mobile.ui.widget.EditView    
    android:id="@+id/login_name"    
    android:layout_width="0dp"    
    android:layout_height="wrap_content"   
    android:layout_gravity="center_vertical"    
    android:layout_marginRight="8dip"   
    android:layout_weight="1"    
    android:background="@null"       
    android:hint="@string/hint_login_name"    
    android:imeOptions="actionNext"    
    android:paddingBottom="8dip"   
    android:singleLine="true"   
    android:textColor="@color/white"   
    android:textColorHint="@color/white_trans_88"    
    android:textCursorDrawable="@null" />

android:layout_weight=”1” 屬性導致過久的測量時間。

優化3

在Theme中給activity添加背景。減少一層繪制

    <style name="AppTheme" parent="AppBaseTheme">
        <item name="android:windowBackground">
        @drawable/bg_homepage
        </item>
    </style>

優化4:

重繪控件,提前為控件繪制背景或形狀,在控件放到布局上時,就已經被繪制好。

這里代碼量較大,我們放到另一篇文章中講: 
http://blog.csdn.net/u010255127/article/details/49702663

最終優化效果

沒有紅色,最高是綠色 
(替換了一些控件和實現方式,不對本文所講述的內容有影響,我們只看過度繪制檢測)

這里寫圖片描述

測試數據

【時間計算】 單位 /ms (測算時間受手機性能影響,數據較為不穩定,需多次測量) 
原始狀況:

onCreate 到 onStart : 381  370 
onCreate 到 onResume :383  373
onStart 到 onResume : 2     3

在theme加背景

onCreate 到 onStart : 274  295
onCreate 到 onResume :277  298
onStart 到 onResume :  3    3

僅修改布局層次(去掉兩個不必要透明布局)

onCreate 到 onStart : 272   276
onCreate 到 onResume :274  279
onStart 到 onResume :  2     3替換自定義 提前繪制控件
onCreate 到 onStart :  289  299  294
onCreate 到 onResume :  292 302  296
onStart 到 onResume :   3    3    2

結論:我們可以很清晰看到當我們把背景設置到Theme中時,View繪制時間減少的非常明顯。 
去掉不必要的布局和View,雖然效果甚微,但也減少了。

最后,雖然提前繪制控件並沒有起到減少繪制時間的作用,甚至還稍加了一點時間(內存中繪圖)。但減少了過度繪制,對界面運行的流暢度起到的作用非常大的。 
另外,我們繪制邏輯還有很大優化的空間,這個任重而道遠……

最后提一小點,WebView里面的Html頁面,過度繪制是檢測不到的,也就是說,如果你的Html頁面里疊加了100層,那過度繪制檢測看起來也是一層。

我所懷疑的是,這一層究竟是表象,只是避開了工具的檢測。還是真的可以起到性能優化作用。對WebView研究甚少,還請大神們研究一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM