Android性能優化-Render篇

前言

本篇文章是udacity上的Android Performace系列視頻-Render篇的課程紀要。html

這個系列是視頻是Google和udacity合做推出的視頻,在Google的Android Performace Pattern系列視頻的基礎上加上了練習的章節,同時還有有趣的過場情節,很是不錯的視頻。java

課程地址:android

https://cn.udacity.com/course/android-performance--ud825性能優化

目錄

  • Draw!
  • Android系統的渲染組件
  • 格柵化 - Rasterization
  • 過分繪製 - Overdraw
  • 避免Overdraw
  • Layouts, Invalidation And Performance
  • 佈局分析工具 - Hierarchy Viewer
  • 優化佈局
  • 總結

DRAW!

Android系統每隔16ms從新繪製一次Activity,也就是說必須在16ms以內完成屏幕刷新的所有邏輯操做,這樣才能達到每秒60幀。工具

PS:每秒60幀是手機硬件決定的,如今大多數手機屏幕刷新頻率在60Hz。1000ms/60Hz = 16.666ms/frame。佈局

若是錯過了16ms,好比花費了24ms才完成計算,那麼就會出現丟幀的狀況。性能

系統準備刷新,但界面尚未準備好,因此用戶盯着同一張圖看了32ms而不是16ms,丟幀狀況下的動畫會讓用戶以爲卡頓。下面讓咱們來看看形成卡頓的緣由以及如何去解決應用中的這些問題。優化

Android系統的渲染組件

Android系統的渲染Pipeline分爲兩個關鍵組件,CPUGPU,二者共同工做在屏幕上繪製圖片。每一個組件都有自身的特定流程,必須遵照這些特定操做規則才能達到效果。動畫

GPU方面,最多見的性能問題是「過分繪製Overdraw」ui

CPU方面,最多見的性能問題是「佈局的渲染效率」

本文咱們將一一介紹,以及如何使用SDK中的可用工具找出拖累應用性能的緣由。

格柵化 - Rasterization

在介紹更多以前,咱們須要先了解一些底層的機制。Android是如何將複雜的XML佈局文件和標記語言轉換成用戶能看懂的圖像的。實際上,這是由格柵化操做來完成的。

格柵化將諸如字符串String、按鈕Button、路徑Path或形狀Shape的一些高級對象拆分到不一樣的像素上在屏幕上進行顯示。格柵化是一個很是費時的操做。GPU的引入就是爲了加快格柵化。

GPU使用一些指定的基礎指令集來繪製多邊形Polygons和紋理Textur,CPU經過OpenGL ES向GPU輸入這些指令。

CPU負責把UI組件計算成多邊形Polygons或紋理Texture,而後交給GPU進行柵格化渲染。

UI組件轉化成一系列多邊形和紋理的過程至關耗時、CPU將數據傳輸給GPU也是很是耗時的動做

因此很明顯,必需要減小轉換的次數已經上傳數據的次數。幸好OpenGL ES API容許數據上傳到GPU後能夠對數據進行保存,當下一次繪製一個按鈕時,只須要在GPU memory中引用它,而後告訴OpenGL如何繪製。

 從底層的角度來看,渲染性能的優化就是儘量快地上傳數據到GPU,而後儘量地在不修改的條件下保存數據。

Android Honeycomb以後,整個UI渲染系統就在GPU中運行。Android系統在下降reduce、從新利用reuse和回收recycle GPU資源方面作了不少工做。

好比任何由主題所提供的資源,例如Bitmaps、Drawables等都是一塊兒打包到統一的紋理當中,而後使用網格工具上傳到GPU,好比Nine Patches。這樣每次你須要繪製這些資源時,都是直接從紋理裏面進行獲取渲染的,大大加快了這些視圖類型的顯示。

固然隨着UI組件的愈來愈豐富,有了更多演變的形態。例如顯示圖片的時候,須要先通過CPU的計算加載到內存中,而後傳遞給GPU進行渲染。文字的顯示更加複雜,須要先通過CPU換算成紋理,而後再交給GPU進行渲染,回到CPU繪製單個字符的時候,再從新引用通過GPU渲染的內容。動畫則是一個更加複雜的操做流程。

好了,在瞭解了GPU繪製的底層原理後,咱們來看一個GPU性能的問題瓶頸 - 過分繪製Overdraw。

過分繪製 - Overdraw

過分渲染指的是屏幕上的某個像素點在同一幀的時間內被繪製了屢次。有些看不見的佈局也進行了繪製,這樣就會浪費GPU資源。

目前流行的一些佈局是一把雙刃劍,帶給咱們漂亮視覺感覺的同時,也形成過分繪製的問題。爲了最大限度提升應用的性能,咱們必須儘可能減小過分繪製。

幸運的是,咱們能夠經過手機設置裏面的開發者選項,打開Show GPU Overdraw的選項,能夠觀察UI上的Overdraw狀況。

藍色,淡綠,淡紅,深紅表明了4種不一樣程度的Overdraw狀況,咱們的目標就是儘可能減小紅色Overdraw,看到更多的藍色區域。(固然最完美的狀況是顯示應用原本的顏色,不過正如前面提到的如今流行的一些佈局爲用戶提供漂亮的視覺感覺,因此某些Overdraw在某種程度上是能夠接受的)。

避免Overdraw

有兩種避免Overdraw的方法:

1、從視圖中清除那些沒必要要的背景和圖片,它們不會在最終渲染圖像中顯示。

能夠從如下方面着手:

一、若是在佈局中有指定背景,那麼將Activity的背景設置爲null。

getWindow().setBackgroundDrawable(null);

二、分析佈局,將layout XML中一些沒必要要的背景屬性去掉。

 

2、對視圖中重疊的屏幕區域進行ClipRect定義,從而下降CPU和GPU的消耗。

Android系統利用了剪輯clipping技術來避免Overdraw,若是能肯定某個對象會被徹底阻擋,那就徹底不必繪製它。這是最重要的性能優化方法之一。對於複雜的自定義view,系統沒法檢查onDraw方法具體會執行什麼操做,這些狀況下,底層系統沒法識別如何去繪製對象。從而有可能會形成屢次繪製。

好比上圖的view,只有最上面的牌是可見的,其餘牌都被擋住了。這就意味着繪製那些重疊的像素就是浪費資源。

對於這個問題,咱們可使用Canvas類中一些特別的方法幫助Android系統識別被遮擋的不須要繪製的部分:

一、Canvas.clipRect - 指定特定的繪製邊界,邊界以外的不進行任何繪製。

若是咱們知道自定義View可見部分的範圍或者遮擋部分的範圍,那麼咱們就能夠定義ClipRect邊界,避免遮擋區域的任何繪製操做。

PS:在使用Canvas.clipRect()的先後記得要調用Canvas.save()和Canvas.restore()。

二、Canvas.quickReject - 判斷給定區域是否徹底在剪輯矩形以外。從而跳過那些非矩形區域內的繪製操做。

Layouts, Invalidation And Performance

一般來講,Android須要把XML佈局文件轉換成GPU可以識別並繪製的對象。這個操做是在DisplayList的幫助下完成的。DisplayList持有全部將要交給GPU繪製到屏幕上的數據信息(包含GPU要繪製的所有對象的信息列表、執行繪製操做的OpenGL命令列表)。

在某個View第一次須要被渲染時,DisplayList會所以而被建立,當這個View要顯示到屏幕上時,咱們會執行GPU的繪製指令來進行渲染。若是你在後續有執行相似移動這個View的位置等操做而須要再次渲染這個View時,咱們就僅僅須要額外操做一次渲染指令就夠了。然而若是你修改了View中的某些可見組件,那麼以前的DisplayList就沒法繼續使用了,咱們須要回頭從新建立一個DisplayList而且從新執行渲染指令並更新到屏幕上。

須要注意的是:任什麼時候候View中的繪製內容發生變化時,都會從新執行建立DisplayList,渲染DisplayList,更新到屏幕上等一系列操做。這個流程的表現性能取決於你的View的複雜程度,View的狀態變化以及渲染管道的執行性能。舉個例子,假設某個Button的大小須要增大到目前的兩倍,在增大Button大小以前,須要經過父View從新計算並擺放其餘子View的位置。修改View的大小會觸發整個ViewHierarcy的從新計算大小的操做。若是是修改View的位置則會觸發ViewHierarch從新計算其餘View的位置。若是佈局很複雜,這就會很容易致使嚴重的性能問題。

Hierarchy Viewer能夠幫助咱們快速可視化整個UI結構,並讓咱們理解這個結構內的獨特視圖的相對渲染性能。

佈局分析工具 - Hierarchy Viewer

Hierarchy Viewer能夠幫助咱們快速可視化整個UI結構,並讓咱們理解這個結構內的獨特視圖的相對渲染性能。咱們能夠經過它來查看佈局、使得佈局儘可能簡單化、扁平化、移除非必要的佈局;同時對渲染相對比較慢的view進行分析,減小Measure、Layout的計算時間。

具體來講,

一、分析頁面佈局結構

查看頁面佈局

二、分析渲染性能

點擊「Venn」按鈕(能夠多點擊幾回讓資源達到平衡,結果更準確)查看記錄每一個節點rendering pipeline的過程,每一個節點的三個圓點從左到右依次是measure、layout、draw的過程。圓點的顏色表示這個節點相對於因此其餘已經概要顯示的節點的性能,分別有綠色、黃色、紅色。綠色表明執行速度快於至少一半以上的其餘視圖節點,黃色表示執行速度屬於比較慢的50%,紅色意味着這是視圖層級中最慢的節點。

對於紅色節點,咱們須要分析它可能存在的問題。顯示紅色的節點是否和理論上是最慢的節點是否一致。有必要說明的是,這裏顯示的是相對性能,可能它的絕對性能並不慢,因此咱們還須要結合實際數字進行分析。

具體教程能夠參考:

Device Setup for Hierarchy Viewer: Device Setup

Hierarchy Viewer Walkthrough

Profiling with Hierarchy Viewer

佈局優化

一、儘可能扁平化佈局。

若是用RelativeLayout和LinearLayout實現一個相同的佈局,經過Hierarchy Viewer能夠分析得出RelativeLayout的性能是高於LinearLayout的。由於RelativeLayout更加地扁平化。

二、去掉多餘layout節點。

咱們知道,佈局的渲染速度是跟節點數呈正比的,因此咱們能夠分析佈局嘗試去掉多餘的節點。也能夠利用如<merge>等標籤來減小咱們佈局的層次。

總結

本文主要介紹了渲染相關的性能優化。分別介紹了Android系統渲染的底層機制和最主要的兩個組件GPU&CPU。

從GPU的角度來講,存在的性能問題是過分繪製Overdraw,能夠利用Show GPU Overdraw來分析,解決方案是修改Layout XML,去掉多餘或重複的背景。若是是自定義View,能夠利用Canvas的ClipRect來限制繪製區域。

從CPU的角度來講,存在的性能問題是佈局渲染的效率,能夠利用Hierarchy Views工具分析佈局和性能,解決方案是修改Layout XML,使得佈局層級減小,儘可能扁平化。

相關文章
相關標籤/搜索