Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android資訊 >> Android性能優化之渲染篇

Android性能優化之渲染篇

編輯:Android資訊

Google近期在Udacity上發布了Android性能優化的在線課程,分別從渲染,運算與內存,電量幾個方面介紹了如何去優化性能,這些課程是Google之前在Youtube上發布的Android性能優化典范專題課程的細化與補充。

下面是渲染篇章的學習筆記,部分內容和前面的性能優化典范有重合,歡迎大家一起學習交流!

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來優化布局。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved