檢測和解決Android應用的性能問題
前言
無論你的應用多么有創新性、有用,如果它卡得要命,或者非常消耗內存,那么每人將會愿意使用它。
因此,性能變得尤為重要。當你忙碌于構建精美的用戶界面或者完成新的特性時,你可能容易忘卻掉一些性能相關的事情。
這也是為什么有Google Play的應用審核機制的原因之一。
這篇文章中,你會看到每個Android工程師需要了解的一些性能問題。你將會學會使用Android SDK提供的、已安裝在你的設備中的工具來測試這些問題是否發生在你自己的應用中。
如果在你的應用中發現了一個性能問題,你肯定會想修復它。我們還會看一看如何使用Android SDK 工具來獲取更多關于那些沒有覆蓋到的性能問題的相關信息。一旦你有了這些信息,你將會對如何提升應用性能有一個更深刻的理解,并且能夠構建出讓用戶喜愛的App。
過度繪制
步驟1 : 問題描述
你應用的用戶界面是連接用戶的紐帶,但是創建漂亮的界面只是挑戰的其中一面,你還需要確保用戶界面流暢的運行。
一個常見的問題就是用戶界面卡頓,出現這種情況的原因可能是overdraw。Overdraw是屏幕上的某個像素在同一幀的時間內被繪制了多次。
例如,想象一下一個有藍色的背景文本,Android不僅會繪制對用戶可見的藍色區域,而是會繪制整個藍色的背景以及上面的文本。這意味著一些像素會被兩次繪制,這就是過度繪制。
一些如上述例子所說的過度繪制示例是不可避免的。然而,過多的多度繪制會引發明顯的性能問題,因此你必須將過度繪制的可能性降到最小。
檢測應用中的過度繪制相對來說比較簡單。大量的過度繪制會引出其他用戶界面相關問題,例如視圖層級過于復雜等。基于這些原因,當你測試你的App的性能問題時,從過度繪制開始是一個明智的選擇。
步驟2 : 檢測過度繪制
好消息是你的Android設備上已經內置了檢測過度繪制的工具。
因此你需要做的第一步就是安裝你要測試的App到你的設備中。然后打開設置頁面,選擇開發選項(Developer Options)->調試GPU 過度繪制(Debug GPU Overdraw),然后選擇“顯示過度繪制區域(Show overdraw area)”。如下圖所示。
這個工具使用色塊來代表不同數量的過度繪制。剩下的事情就是啟動你要測試的應用,然后觀察它的過度繪制情況。
- 沒顏色 : 沒有過度繪制,也就是說一個像素只被繪制了一次。
- 藍色 : 過度繪制了一次,也就是一個像素點被繪制了兩次。
- 綠色 : 過度繪制了2次. 也就是一個像素點被繪制了三次,通常,你需要集中精力優化過度繪制次數大于等于2次的情況。
- 淺紅色 : 過度繪制3次。這取決于你的應用,小范圍的3次過度繪制可能是不可避免的,但是如果你看到了中等或者大量的紅色區域那么你就需要查找出現這個問題的原因了。
- 深紅色 : 過度繪制4次,像素點被繪制了5次,甚至更多次。出現這種問題你絕逼要找到原因,并且解決它。 </ul>
- 測量
- 布局
- 繪制 </ol>
- Tree View: **** 視圖層級窗口,每個節點代表了一個View;
- Tree Overview: 整個視圖層級的縮略布局;
- Layout View: 當前視圖層級的輪廓. </ul>
- 用于測量的時間
- 用于布局的時間
- 用于繪制的時間 </ul>
- 綠色 代表該View的渲染速度至少要快于一半以上的其他參與測試的節點。例如,一個在布局位置上的綠色的圓點代表它的布局速度要快于50%以上的其他節點;
- 黃色 代表該View慢于50%以上的其他節點;
- 紅色 代表該View的渲染速度比其他所有參與測試的節點都慢。 </ul>
- 原文鏈接 : Detect and Resolve Performance Problems on Android
- 譯文出自 : 開發技術前線 www.devtf.cn
- 譯者 : Mr.Simple
步驟3 : 最小化過度繪制
一旦你發現了某個區域有嚴重的過度繪制,最簡單的方法就是打開你應用的xml文件找到過度重疊的區域,特別是那些不可見的drawable對象和被繪制在其他控件上的背景,以此來降低這些地方的過度繪制。
你也應該查找那些背景屬性設置為白色,并且它的父視圖背景也設置為白色的區域。所有這些都會引起嚴重的過度繪制。
Android系統能自動的降低一些簡單的過度繪制,但是這些對于復雜的自定義View并沒有什么價值,因為Android不會知道你如何繪制你的內容。
如果你在App中使用了復雜的自定義View,你可以為使用clipRect函數為你的視圖定義可繪制區域的邊界。更新相關信息可以參考official Android
documentation.
## 2. Android 圖形渲染
步驟1 : 問題描述
另一個常見的性能問題就是應用的視圖層級。為了渲染每個視圖,Android都會經歷這三個階段 :
花在這三個階段的時間與View層級中的View的數量成正比,這就意味著降低App渲染時間的最簡單的方法就是識別和移除那些并沒有什么卵用的UI元素。
即使在你的視圖層級上的所有View都是必須的,不同的布局方式也可能對測量過程產生重要的影響。通常來說,你的視圖層級越深,花在測量視圖的時間就越長。
在視圖渲染期間,每個View都要向它的父View提供它自己的尺寸。如果父view發現了任意一個尺寸問題,那么它會強制要求所有的子視圖重新測量。
即使沒有錯誤發生,重新測量也可能出現。例如,為了正確的進行布局RelativeLayout通常會對它們的子視圖進行兩次測量。子視圖使用了layout_weight屬性的LinearLayout也會對它的子視圖進行兩次測量。
這些都取決于你的布局方式,測量和重新測量的代價非常昂貴,它會嚴重影響你的渲染速度。
確保你的用戶界面渲染流暢的關鍵就是移除任何非必須的View以及減少你的View層級。
Hierarchy Viewer是一個能夠將你完整的View層級可視化的工具,這個工具能夠幫助你發現冗余的View以及嵌套的布局。
步驟2:使用 Hierarchy Viewer
在我們進一步了解Hierarchy Viewer之前,你需要知道它的一些規則。首先Hierarchy Viewer只能與正在運行的App進行交互,而不是你的源代碼。這就是說你需要將App安裝到你的設備或者模擬器上。
還有一個最重要的問題,就是默認情況下Hierarchy Viewer只能與運行開發版Android系統的設備進行交互(譯者注: 一般來說,使用模擬器即可)。如果你沒有開發設備,那你需要添加ViewServer
class到你的應用中。
了解這些之后就讓我們打開Android Studio,并且選擇”tools” -> “Android” -> “Android Device Monitor”,如圖所示。
然后點擊Hierarchy View按鈕,如下圖所示。
屏幕左邊的Windows標簽下列出了所有Android設備和模擬器。選擇你的設備后,你會看到你設備上運行的所有進程。選中你要檢測的進程,然后你會看到三個自動更新的視圖層級區域。
這三個窗口提供了視圖層級的三個不同可視化展示。
Hierarchy View中有三個窗口。如果你在一個窗口中選擇了一個View,那么它會在另外兩個中高亮顯示。你能同時使用這三個窗口查找View層級中的冗余視圖。
如果你不確定一個View是否是UI界面中的必須元素,最簡單的方法就是到Tree View窗口點擊這個節點。你將會看到該View是如何顯示在屏幕的預覽,此時你就可以確切地知道該View是否是必須的。
但是即使一個View對最終的渲染效果有貢獻也并不意味著它不會引起嚴重的性能問題。你已經看到了如何通過Hierarchy Viewer來找到明顯的嵌套布局,但是如果這引起的性能問題并不那么明顯呢?或者還有其他的原因使得該視圖渲染得非常慢?
好消息就是你還可以通過Hierarchy Viewer來剖析每個View在不同的渲染階段的耗時。當性能問題的原因不那么明顯時,這是你發現問題的另一途徑。
下個章節我將為你展示如何通過Hierarchy Viewer來剖析每個View的渲染時間來找到潛伏在問題表面的性能問題。
步驟3 : 節點的性能分析
定位你的用戶界面瓶頸的最簡單方法就是收集每個View分別完成測量、布局、繪制的時間。
你不僅可以通過Hierarchy Viewer收集這些信息,Hierarchy Viewer還可以通俗易懂地向你展示這些數據,因此你可以通過這種形式來找到性能問題。
Hierarchy Viewer默認并不會顯示渲染時間。你需要到Tree View窗口添加這個信息,然后選擇你想要測試的根節點。下一步,在Hierarchy Viewer上點擊由綠、紅、紫的三個圓形色塊組成的按鈕,如圖所示。
三個圓點色塊就會顯示在每個節點上,從左到右,這些圓點分別代表 :
每個圓點都有顏色 :
當收集了這些數據之后,你不僅知道哪些View需要優化,你還會確切地知道是在渲染的哪個階段導致的問題。
哪些黃色、紅色的地方就是你需要開始優化的地方,這些性能指標與該視圖層級下的其他剖析節點也有關系。換句話說,你肯定會有一些視圖渲染得比其他的慢。
在開始改良你的View相關的代碼之前,摸著你的良心問一句該View渲染得比其他視圖慢是否有一個合理的原因,如果答案是否定的,那么就開始你的View優化之旅吧。
3. Memory Leaks 內存泄漏
步驟1:問題描述
Android是一個自動管理內存的開發環境,不要讓這個句話蒙蔽了,因為內存泄漏依舊是可能發生的。這是因為垃圾回收器只會移除那些不可達的對象。如果它不是一個不可達的對象,那么該對象就不會被釋放掉。
這些不可達的對象陰魂不散,聚集在你的堆內存中,占用App的內存控件。如果你繼續泄漏對象,那么可用的內存空間將會越來越小,GC操作就會頻繁觸發。
有兩個原因表明這是一個壞消息。首先,GC操作通常不會明顯地影響你的App性能,但是當內存控件較小時大量的GC操作會使你的App變慢,此時UI就不會那么流暢了。第二問題是移動設備的內存空間相對來說較小,因此內存泄漏會快速地升級為內存溢出,導致應用Crash。
內存泄漏難以被檢測出。可能只有當用戶開始抱怨你的應用時你才能發覺內存泄漏問題。幸運地是,Android SDK提供了一些有用的工具來讓你找到這些問題。(譯者注 : Square的開源庫LeakCanary是查找內存泄漏的優秀工具,強烈建議大家使用)。
步驟2 : 內存監視器 (Memory Monitor)
Memory Monitor是一個能夠實時獲取應用內存使用情況的工具。需要注意的是這個工具只能作用于正在運行的應用,因此確保你的要測試的應用已經安裝到你的設備中,并且你的設備已經連接到你的電腦上。
Memory Monitor已經內置在Android Studio中,因此你可以點擊Android Studio的底部的”Memory”這個tab來切換到內存監視頁面。當你切換到該頁面的時候,Memory Monitor就開始記錄你的內存使用情況了。
如果Memory Monitor沒有開始記錄,那么確保你的設備是已經被選中的狀態。
如果Memory Monitor提示No debuggable applications,那么你可以打開Android Studio的”Tools”菜單,選擇”Android”,然后確保選中了Enable adb integration。這個功能還不是很穩定,所以有時候你需要手動切換它的狀態。你也可以斷開設備與電腦的連接,然后再重連,這樣可能就OK了。
一旦Memory Monitor檢測到正在運行的應用,它就會顯示這個應用的內存使用情況。已使用的內存會被表示為深藍色,未分配的內存則會變為淺藍色。
花一些時間與你的設備交互,并且關注你的內存使用情況。最終已分配的內存會增長,直到沒有內存可用。此時,系統就會釋放觸發GC釋放內存,當你看到已分配的內存明顯的下降時就代表GC操作被觸發了。
GC通常情況下會將無用的內存釋放掉,但是當你看到App在短時間內快速增長或者GC變得非常頻繁,此時你就需要倍加小心了,這就是發生內存泄漏的信號!
如果你通過Memory Monitor來追蹤一個可疑的內存泄漏問題,你可能會看到Android系統會為你的App增大可用內存,TODO : 。
最終,你可能會看到你的App消耗了非常多的內存以至于系統無法再給你的應用更多的可用內存。如果你看到這種場景,那么說明你在內存使用上犯了很嚴重的錯誤。
步驟3 : Android Device Monitor
另一個能夠幫助你收集更新關于內存泄漏信息和其他內存相關問題的工具是Android Device Monitor的DDMMS工具下的Heap。
Heap工具能夠通過顯示系統為你分配了多少內存來幫助你診斷內存泄漏問題。正如上面提到的,如果已分配的內存不斷地增長,那么這是發生內存泄漏的明顯信號。
但是這個工具還提供了許多關于你的應用堆內存使用情況的數據,包含你的App內分配的各種對象、分配的對象數量以及這些對象占用了多少空間。這些額外的信息對于你追蹤內存泄漏極為有用。
你可以在Android Device Monitor工具中選擇DDMS,在Devices中選擇你要檢測的App。然后選擇Heap標簽,如圖所示。然后花一些時間與你的App進行交互以收集內存信息。
heap輸出信息會在GC事件之后,因為你可以手動點擊Cause GC來觸發GC,使得Heap內存數據盡快地顯示出來。
一旦GC事件被觸發了,heap標簽下就會更新App的堆內存使用信息,這些信息會在每次GC時更新。
## 總結
在這篇文章中,我們學習了一些開發中最常見的性能問題,過度繪制、內存泄漏、緩慢的UI渲染。
相信你已經掌握了如何使用工具來檢查這些問題,以及如何獲取更新的信息來判斷你的應用中是否出現了這些性能問題。你有越多的信息,就越容易追蹤到問題的原因并且修復它。
Android SDK有很多工具可以供你診斷和定位性能問題。如果你想學習更多這方面的知識,你可以訪問u這兩篇官方文檔 Traceview and dmtracedump和 Allocation Tracker.