Android性能優化之渲染

Google近期在Udacity上發佈了Android性能優化的在線課程,目前有三個篇章,分別從渲染,運算與內存,電量三個方面介紹瞭如何去優化性能,這些課程是Google以前在Youtube上發佈的Android性能優化典範專題課程的細化與補充。html

下面是渲染篇章的學習筆記,部份內容和前面的性能優化典範有重合,歡迎你們一塊兒學習交流!android

引用自 http://www.howcode.cn canvas

1)Why Rendering Performance Matters

如今有很多App爲了達到很華麗的視覺效果,會須要在界面上層疊不少的視圖組件,可是這會很容易引發性能問題。如何平衡Design與Performance就很須要智慧了。性能優化

2)Defining ‘Jank’

大多數手機的屏幕刷新頻率是60hz,若是在1000/60=16.67ms內沒有辦法把這一幀的任務執行完畢,就會發生丟幀的現象。丟幀越多,用戶感覺到的卡頓狀況就越嚴重。佈局

3)Rendering Pipeline: Common Problems

渲染操做一般依賴於兩個核心組件:CPU與GPU。CPU負責包括Measure,Layout,Record,Execute的計算操做,GPU負責Rasterization(柵格化)操做。CPU一般存在的問題的緣由是存在非必需的視圖組件,它不只僅會帶來重複的計算操做,並且還會佔用額外的GPU資源。性能

4)Android UI and the GPU

瞭解Android是如何利用GPU進行畫面渲染有助於咱們更好的理解性能問題。一個很直接的問題是:activity的畫面是如何繪製到屏幕上的?那些複雜的XML佈局文件又是如何可以被識別並繪製出來的?學習

Resterization柵格化是繪製那些Button,Shape,Path,String,Bitmap等組件最基礎的操做。它把那些組件拆分到不一樣的像素上進行顯示。這是一個很費時的操做,GPU的引入就是爲了加快柵格化的操做。測試

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

然而每次從CPU轉移到GPU是一件很麻煩的事情,所幸的是OpenGL ES能夠把那些須要渲染的紋理Hold在GPU Memory裏面,在下次須要渲染的時候直接進行操做。因此若是你更新了GPU所hold住的紋理內容,那麼以前保存的狀態就丟失了。動畫

在Android裏面那些由主題所提供的資源,例如Bitmaps,Drawables都是一塊兒打包到統一的Texture紋理當中,而後再傳遞到GPU裏面,這意味着每次你須要使用這些資源的時候,都是直接從紋理裏面進行獲取渲染的。固然隨着UI組件的愈來愈豐富,有了更多演變的形態。例如顯示圖片的時候,須要先通過CPU的計算加載到內存中,而後傳遞給GPU進行渲染。文字的顯示比較複雜,須要先通過CPU換算成紋理,而後交給GPU進行渲染,返回到CPU繪製單個字符的時候,再從新引用通過GPU渲染的內容。動畫則存在一個更加複雜的操做流程。

爲了可以使得App流暢,咱們須要在每幀16ms之內處理完全部的CPU與GPU的計算,繪製,渲染等等操做。

5)GPU Problem: Overdraw

Overdraw(過分繪製)描述的是屏幕上的某個像素在同一幀的時間內被繪製了屢次。在多層次重疊的UI結構裏面,若是不可見的UI也在作繪製的操做,會致使某些像素區域被繪製了屢次。這樣就會浪費大量的CPU以及GPU資源。

當設計上追求更華麗的視覺效果的時候,咱們就容易陷入採用複雜的多層次重疊視圖來實現這種視覺效果的怪圈。這很容易致使大量的性能問題,爲了得到最佳的性能,咱們必須儘可能減小Overdraw的狀況發生。

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

藍色,淡綠,淡紅,深紅表明了4種不一樣程度的Overdraw狀況,咱們的目標就是儘可能減小紅色Overdraw,看到更多的藍色區域。

6)Visualize and Fix Overdraw - Quiz & Solution

這裏舉了一個例子,經過XML文件能夠看到有好幾處非必需的background。經過把XML中非必需的background移除以後,能夠顯著減小布局的過分繪製。其中一個比較有意思的地方是:針對ListView中的Avatar ImageView的設置,在getView的代碼裏面,判斷是否獲取到對應的Bitmap,在獲取到Avatar的圖像以後,把ImageView的Background設置爲Transparent,只有當圖像沒有獲取到的時候才設置對應的Background佔位圖片,這樣能夠避免由於給Avatar設置背景圖而致使的過分渲染。

總結一下,優化步驟以下:

  • 移除Window默認的Background
  • 移除XML佈局文件中非必需的Background
  • 按需顯示佔位背景圖片

7)ClipRect & QuickReject

前面有提到過,對不可見的UI組件進行繪製更新會致使Overdraw。例如Nav Drawer從前置可見的Activity滑出以後,若是還繼續繪製那些在Nav Drawer裏面不可見的UI組件,這就致使了Overdraw。爲了解決這個問題,Android系統會經過避免繪製那些徹底不可見的組件來儘可能減小Overdraw。那些Nav Drawer裏面不可見的View就不會被執行浪費資源。

可是不幸的是,對於那些過於複雜的自定義的View(一般重寫了onDraw方法),Android系統沒法檢測在onDraw裏面具體會執行什麼操做,系統沒法監控並自動優化,也就沒法避免Overdraw了。可是咱們能夠經過canvas.clipRect()來幫助系統識別那些可見的區域。這個方法能夠指定一塊矩形區域,只有在這個區域內纔會被繪製,其餘的區域會被忽視。這個API能夠很好的幫助那些有多組重疊組件的自定義View來控制顯示的區域。同時clipRect方法還能夠幫助節約CPU與GPU資源,在clipRect區域以外的繪製指令都不會被執行,那些部份內容在矩形區域內的組件,仍然會獲得繪製。

除了clipRect方法以外,咱們還可使用canvas.quickreject()來判斷是否沒和某個矩形相交,從而跳過那些非矩形區域內的繪製操做。

8)Apply clipRect and quickReject - Quiz & Solution

上面的示例圖中顯示了一個自定義的View,主要效果是呈現多張重疊的卡片。這個View的onDraw方法以下圖所示:

打開開發者選項中的顯示過分渲染,能夠看到咱們這個自定義的View部分區域存在着過分繪製。那麼是什麼緣由致使過分繪製的呢?

9)Fixing Overdraw with Canvas API

下面的代碼顯示瞭如何經過clipRect來解決自定義View的過分繪製,提升自定義View的繪製性能:

下面是優化事後的效果:

10)Layouts, Invalidations and Perf

Android須要把XML佈局文件轉換成GPU可以識別並繪製的對象。這個操做是在DisplayList的幫助下完成的。DisplayList持有全部將要交給GPU繪製到屏幕上的數據信息。

在某個View第一次須要被渲染時,Display List會所以被建立,當這個View要顯示到屏幕上時,咱們會執行GPU的繪製指令來進行渲染。

若是View的Property屬性發生了改變(例如移動位置),咱們就僅僅須要Execute Display List就夠了。

然而若是你修改了View中的某些可見組件的內容,那麼以前的DisplayList就沒法繼續使用了,咱們須要從新建立一個DisplayList並從新執行渲染指令更新到屏幕上。

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

11)Hierarchy Viewer: Walkthrough

Hierarchy Viewer能夠很直接的呈現佈局的層次關係,視圖組件的各類屬性。 咱們能夠經過紅,黃,綠三種不一樣的顏色來區分佈局的Measure,Layout,Executive的相對性能表現如何。

12)Nested Hierarchies and Performance

提高佈局性能的關鍵點是儘可能保持佈局層級的扁平化,避免出現重複的嵌套佈局。例以下面的例子,有2行顯示相同內容的視圖,分別用兩種不一樣的寫法來實現,他們有着不一樣的層級。

下圖顯示了使用2種不一樣的寫法,在Hierarchy Viewer上呈現出來的性能測試差別:

13)Optimizing Your Layout

下圖舉例演示瞭如何優化ListItem的佈局,經過RelativeLayout替代舊方案中的嵌套LinearLayout來優化佈局。

相關文章
相關標籤/搜索