這是來自一位粉絲「MeloDev」的投稿,講真,我這裡投稿的不少,但是隻有我自己覺得很不錯的才會通過,這篇文章我覺得對大家有用,而且性能優化也算是我面試必問的一個話題了,是以這裡推薦給大家。
寫在前面
公司給了我一周的時間去學習Android性能的優化,參考了張明雲老師的一片文章,并且用公司的實際項目進行測試(附有截圖),還進行了一些知識點,注意事項以及很多網址連結的補充,希望這篇博文能讓做性能測試的朋友們少走一些彎路。
轉載注明出處。
性能名額
1. 布局複雜度:布局複雜會導緻布局需要更長的時間,進而導緻進入應用慢、頁面切換慢;
2. 耗電量:耗電量大會導緻機器發熱、縮短機器的有效使用時長;
3. 記憶體:記憶體消耗大會導緻頻繁GC,GC時會暫停其它工作,導緻頁面卡頓;記憶體洩露會導緻剩餘可用記憶體越來越小;記憶體不足會導緻應用異常;
4. 網絡:頻繁的網絡通路會導緻耗電和影響應用的性能;網絡互動資料大小會影響網絡傳輸的效率;
5. 程式執行效率:糟糕的代碼會嚴重影響程式的運作效率,UI線程過多的任務會阻塞應用的正常運作,長時間持有某個對象會導緻潛在的記憶體洩露,頻繁的IO操作、網絡操作而不用緩存會嚴重影響程式的運作效率。
一、布局複雜度的優化
關于布局的優化,主要分兩個大方向
1. 實作相同界面效果并且層級結構相同時,選用何種Layout最好
在Android中單獨的布局性能:
FrameLayout>LinearLayout>RelativeLayout
可供參考的網址:「LinearLayout與RelativeLayout的性能比較」
總結:
- RelativeLayout會讓子View調用2次onMeasure,LinearLayout 在有weight時,也會調用子View2次onMeasure;
- RelativeLayout的子View如果高度和RelativeLayout不同,則會引發效率問題,當子View很複雜時,這個問題會更加嚴重。如果可以,盡量使用padding代替margin;
- 在不影響層級深度的情況下,使用LinearLayout和FrameLayout而不是RelativeLayout;
- 使用組合控件性能要好于兩個獨立控件,比如一個文本旁邊有一個圖檔,這中情況最好要用DrawableLeft的這種屬性設定圖檔;
2. 減少布局的層級結構
- HierarchyViewer—可檢視布局層次結構,View繪制時耗時。
「HierarchyViewer的使用」
- 無線UIViewer—強烈推薦App工具,可在手機端直接實作HierarchyViewer的功能,檢視任意界面的UI布局。
「無線UIViewer下載下傳」
測試圖檔如下:
目前界面的UI布局層級如上圖所示
總結:
- 一些複用性很高的布局檔案,比如一個App的标題欄,建議使用布局重用include标簽,友善引入和共同管理。
- 觀察上圖第三個層級和第四個層級,無論是Layout類型,還是所覆寫的坐标點,都是重合的,因為父FrameLayout作為一個Container,子FrameLayout作為一個子View的跟布局,這種情況,可使用merge标簽進行布局層級的優化。
- 有些在特定情況下才會出現的界面,比如聯網之後,或者未必百分之百出現的界面,可用ViewStub标簽進行懶加載,性能明顯要優于加載出這個界面然後gone掉。
布局優化相關網址:
「三種優化标簽的使用情景和優勢—張業興 」
「布局優化标簽的源碼分析」
有關布局優化的一些基礎知識準備(郭霖老師的兩篇部落格):
「Android LayoutInflater原理分析,帶你一步步深入了解View(一) 」
「Android視圖繪制流程完全解析,帶你一步步深入了解View(二)」
二、Android開發者模式—GPU過渡繪制
GPU過度繪制定義:
如果你粉刷過一個房間或一所房子,就會知道給牆壁塗上顔色需要做大量的工作。假如你還要重新粉刷一次的話,第二次粉刷的顔色會覆寫住第一次的顔色,第一次的顔色就永遠不可見了,等于你第一次粉刷做的大量工作就完全被浪費掉。這太可怕了。
同樣的道理,如果在你的應用程式中浪費精力去繪制一些東西同樣會産生性能問題。過度繪制這個名詞就是用來描述螢幕上一個像素在單個幀中被重繪了多少次。
GPU過度繪制就指的是在螢幕一個像素上繪制多次(超過一次),GPU過度繪制或多或少對性能有些影響。
GPU過度繪制分析:
過度繪制其實是一個性能和設計的交叉點。我們在設計上追求很華麗的視覺效果,但一般來說這種視覺效果會采用非常多的層疊元件來實作,這時候就會帶來過度繪制的問題。我們再來看看具體顯示在Android界面層級關系:
當我們來繪制一個界面時,會有一個windows,然後是建立Activity,在Activity裡可以建立多個view,或view group,view也可以嵌套view。這些元件從上到下分布,上面的元件是可以被使用者看見的,而在下面的元件是不可見的,但是我們依然要花很多時間去繪制那些不可見的元件,因為在某些時候,它也可能會顯示出來。
檢測過度繪制:
設定-開發者選項-調試GPU過度繪制-顯示過度繪制區域(過度渲染等,不同機器可能不同)
測試的顔色辨別含義:
項目測試截圖:
可以看到項目中并不存在太大問題,有關減少過度繪制的一些建議:
1. 太多重疊的背景
這個問題其實最容易解決,建議前期在設計時盡量保持整體背景統一,另外開發可以檢查你在布局和代碼中設定的背景,有些背景是被隐藏在底下的,它永遠不可能顯示出來,這種沒必要的背景一定要移除,因為它很可能會嚴重影響到app的性能。
2. 太多重疊的view
第一個建議是:使用ViewStub來加載一些不常用的布局,它是一個輕量級且預設不可見的視圖,可以動态的加載一個布局,隻有你用到這個重疊着的view的時候才加載,推遲加載的時間。第二個建議是:如果使用了類似viewpager+Fragment這樣的組合或者有多個Fragment在一個界面上,需要控制Fragment的顯示和隐藏,盡量使用動态地Inflation view,它的性能要比SetVisiblity好。
3. 複雜的Layout層級
這裡的建議比較多一些,首先推薦用Android提供的布局工具Hierarchy
三、Android中耗電量的測試
「深入淺出Android App耗電量統計」
測試截圖:
本人認為這一點沒有過多補充的,大多數App都不會消耗過多的電量。
四、記憶體、CPU、GPU
應用運作時記憶體使用情況檢視:Android Studio—Memory/CPU/GPU
通常這種測試應該使用一個自動化工具(monkey)去不停的點選App,或者切換界面,來觀察記憶體、cpu的情況。
1. 記憶體
在地圖界面不斷地重新整理,正常的記憶體成鋸齒狀分布。
需要注意的情況:
出現了針狀分布,說明記憶體發生了突變,如果記憶體峰值不能降下來,就說明出現了記憶體溢出,就值得引起我們的關注了。
2. CPU
測試圖檔:
3. GPU
Android Studio 1.4增加一項新功能:分析GPU渲染功能。作者詳細講解這一新功能的分析方法。
在GPU頁籤下,可以在螢幕上看到圖形化顯示的渲染每幀所花費的時間。圖形中每條都表示被渲染的一幀。顔色表示程序的不同周期:
繪畫(藍色)
表示View#onDraw()方法。那部分建立/更改DisplayList對象,然後轉換成GPU能夠了解的OpenGL指令。高的條形可能是視圖複雜,而要求更多的時間繪制它們的顯示清單,而許多視圖在短時間内就失效了。
準備(紫色)
在Lollipop中,加入另一個線程,以幫助UI線程渲染更快。這個線程叫:RenderThread。它的責任是轉換顯示清單為OpenGL指令,再發送給GPU。這樣在渲染過程中,UI線程可以開始處理下一個幀。這時UI線程将所有資源傳送給RenderThread。如果有許多資源要傳遞(如許多/繁重顯示清單),這一步可能需要較長時間。
處理(紅色)
執行顯示清單産生OpenGL指令。由于需要視圖重繪,如果有許多/複雜顯示清單要執行轉換,這一步可能需要較長時間。當視圖無效或是移動時,都要要重繪視圖。
執行(黃色)
發送OpenGL指令到GPU。由于CPU發送這些緩存的指令到GPU,并期待收回幹淨緩存,這就阻塞調用了。緩存數量有限,并且GPU也很忙
——
CPU會發現自己必須先等待緩存釋放。是以,如果在這一步我們見高的條形,就可能意味着GPU在繪制UI時非常忙,這個繪制在短時間内太複雜了。
測試截圖:
結論:
可以通過切換界面,看圖形的峰值和顔色去判斷繪制View每個階段所花費的時間,然後根據你的需求進行優化。
五、程式的執行效率
- 靜态代碼檢查工具:Android studio—Analyze—Inspect Code…/Code cleanup… ,用于檢測代碼中潛在的問題、存在效率問題的代碼段并提供改善方案;
- DDMS—TraceView,用于查找程式運作時具體耗時在哪;
- StrictMode:用于查找程式運作時具體耗時在哪,需要內建到代碼中;
六、知名的三方性能優化工具
1. LeakCanary
LeakCanary是一個檢測記憶體洩露的開源類庫。你可以在 debug
包種輕松檢測記憶體洩露。強烈推薦LeakCanary,大多數公司都在使用它進行記憶體洩漏的測試。
以下是我找到的學習資料,寫的非常棒:
「LeakCanary: 讓記憶體洩露無所遁形」
「LeakCanary 中文使用說明」
具體使用請參考以上兩個連結,下面給出一個測試截圖,供大家直覺感受其便捷和強大的功能。
結論: LeakCanary非常直覺的展現了MainActivity出現了記憶體洩漏,并且指出引用路徑中的哪個引用是不該有的,然後修複問題。總而言之非常好用,處理記憶體洩漏首選的工具。
2. GT
GT是騰訊開發的一款APP的随身調測平台,利用GT,可以對CPU、記憶體、流量、點亮、幀率/流暢度進行測試,還可以檢視開發日志、crash日志、抓取網絡資料包、APP内部參數調試、真機代碼耗時統計等等,需要說明的是,應用需要內建GT的sdk後,GT這個apk才能在應用運作時對各個性能進行檢測。
「GT官方網址」
下面是使用GT測試項目的截圖: