Android設備作為一種移動設備,無論是記憶體還是CPU的性能都受到了很大的限制,這導致Android程式的性能問題異常突出,隨著產品的不斷更新迭代,對於性能優化提出了更高的要求。本篇文章從穩定性、流暢性、耗損、安裝包大小四個方面對Android開發提供了一些容易上手、切實有效的性能優化方法,為An ...
Android設備作為一種移動設備,無論是記憶體還是CPU的性能都受到了很大的限制,這導致Android程式的性能問題異常突出,隨著產品的不斷更新迭代,對於性能優化提出了更高的要求。本篇文章從穩定性、流暢性、耗損、安裝包大小四個方面對Android開發提供了一些容易上手、切實有效的性能優化方法,為Android開發中有關性能優化方面的學習提供一個參考。
1.穩定性(解決記憶體溢出、崩潰等問題),記憶體優化
瞭解記憶體如何分配和回收機制,對記憶體優化會有一定的認識和掌握。可以藉助記憶體分析工具,方便定位需要記憶體優化的代碼。(1)Memory Monitor 工具:
Android Studio自帶的一個記憶體監視工具,它可以很好地幫助我們進行記憶體實時分析。通過點擊Android Studio右下角的Memory Monitor標簽,打開工具可以看見較淺藍色代表free的記憶體,而深色的部分代表使用的記憶體從記憶體變換的走勢圖變換,可以判斷關於記憶體的使用狀態,例如當記憶體持續增高時,可能發生記憶體泄漏;當記憶體突然減少時,可能發生GC等(2)Memory Analyzer 工具:
MAT(Memory Analyzer Tool) 是一個快速,功能豐富的 Java Heap 分析工具,通過分析 Java 進程的記憶體快照 HPROF 分析,從眾多的對象中分析,快速計算出在記憶體中對象占用的大小,查看哪些對象不能被垃圾收集器回收,並可以通過視圖直觀地查看可能造成這種結果的對象。 檢測步驟如下:(a)屏幕多次翻轉,出現記憶體持續增高時。點擊 Dump java Heap就會生成運行記憶體快照hprof文件。
(b)然後將APP完全退出,重新啟動,打開Android Monitor 再次點擊Dump java Heap 生成一份還沒操作(旋轉屏幕)前的記憶體快照hprof文件。現在就已經生成好了2份hprof文件, 一份是沒有旋轉過屏幕的 ,一份是旋轉過屏幕多次的。
(c)然後選中Android Studio 最左邊的Captures 進行將hprof文件導出。導出的時候需要選擇保存的目錄以及文件名。
(d)打開MAT ,導入我們的2個hprof文件 Open File-->選擇文件-->Leak Suspects Report-->Finish
可以通過檢索包名,查看某個類的實例個數和所在記憶體數據,還可以查看被引用的記憶體數據。
Objects:實例個數
Shallow Heap:所占記憶體大小
Retained Heap:釋放後能回收多少記憶體
(3)LeakCanary工具:
簡單,傻瓜式操作。可以在GitHup官網查閱https://github.com/square/leakcanary,我們可以在Gradle文件里添加依賴。這個工具是Square公司在Github開源的。行業內不是有一句話嘛,Square出品必屬精品,主流的庫像okhttp、Picasso、retrofit、Dagger等都出自Square之手。說到這不得不讓我聯想到一位在Android開發領域神一般存在的人物,他就是大名鼎鼎的Jake Wharton(傑克.沃頓),ButterKnife的創造者,也參與貢獻了Retrofit, okhttp等。
(4)Android Lint 工具:
Android Lint Tool 是Android Sutido種集成的一個Android代碼提示工具,它可以給你佈局、代碼提供非常強大的幫助。 硬編碼會提示以級別警告,例如:在佈局文件中寫了三層冗餘的LinearLayout佈局、直接在TextView中寫要顯示的文字、字體大小使用dp而不是sp為單位,就會在編輯器右邊看到提示。使用Android Studio的lint可以清除無用的資源文件(點擊菜單欄的Analyze -> Run Inspection by Name, 輸入unused resource)。 當然以上都是一個簡單的舉例,Lint的功能非常強大,大家應該養成寫完代碼查看Lint的習慣,這不僅讓你及時發現代碼種隱藏的一些問題,更能讓你養成良好的代碼風格,要知道,這些Lint提示可都是Google大牛們汗水合智慧的結晶。
小結
影響穩定性的原因很多,比如記憶體使用不合理、代碼異常場景考慮不周全、代碼邏輯不合理等,都會對應用的穩定性造成影響。其中最常見的兩個場景是:Crash 和 ANR,這兩個錯誤將會使得程式無法使用。所以做好Crash全局監控,處理閃退同時把崩潰信息、異常信息收集記錄起來,以便後續分析;合理使用主線程處理業務,不要在主線程中做耗時操作,防止ANR程式無響應發生。
2.流暢性(卡頓優化)
卡頓的場景通常是發生在用戶交互體驗最直接的方面。影響卡頓的兩大因素,分別是界面繪製和數據處理。- 界面繪製:主要原因是繪製的層級深、頁面複雜、刷新不合理,由於這些原因導致卡頓的場景更多出現在 UI 和啟動後的初始界面以及跳轉到頁面的繪製上。
- 數據處理:導致這種卡頓場景的原因是數據處理量太大,一般分為三種情況,一是數據在處理 UI 線程,二是數據處理占用 CPU 高,導致主線程拿不到時間片,三是記憶體增加導致 GC 頻繁,從而引起卡頓。
分析UI卡頓:
我們知道Android的繪製步驟是:Measure、Layout、Draw,所以佈局的層級越深、元素越多、耗時也就越長。還有就是Android操作系統每隔 16ms 發出 VSYNC 信號,觸發對 UI 進行渲染,如果每次渲染都成功,這樣就能夠達到流暢的畫面所需的 60FPS。如果某個操作花費的時間是 24ms ,系統在得到 VSYNC 信號時就無法正常進行正常渲染,這樣就發生了丟幀現象。那麼用戶在 32ms 內看到的會是同一幀畫面,無法在 16ms 完成渲染,最終引起刷新不及時。
總結以上,兩個根本原因:1、繪製任務太重,繪製一幀內容耗時太長;2、主線程太忙,根據系統傳遞過來的 VSYNC 信號來時,還沒準備好數據,導致丟幀。
(1)佈局優化
在Android種系統對View進行測量、佈局和繪製時,都是通過對View數的遍歷來進行操作的。如果一個View數的高度太高就會嚴重影響測量、佈局和繪製的速度。Google也在其API文檔中建議View高度不宜哦過10層。現在版本種Google使用RelativeLayout替代LineraLayout作為預設根佈局,目的就是降低LineraLayout嵌套產生佈局樹的高度,從而提高UI渲染的效率。- 佈局復用,使用<include>標簽重用layout;
- 提高顯示速度,使用<ViewStub>延遲View載入;
- 減少層級,使用<merge>標簽替換父級佈局;
-
註意使用wrap_content,會增加measure計算成本;
-
刪除控制項中無用屬性;
(2)繪製優化
過度繪製是指在屏幕上的某個像素在同一幀的時間內被繪製了多次。在多層次重疊的 UI 結構中,如果不可見的 UI 也在做繪製的操作,就會導致某些像素區域被繪製了多次,從而浪費了多餘的 CPU 以及 GPU 資源。如何避免過度繪製?-
佈局上的優化。移除 XML 中非必須的背景,移除 Window 預設的背景、按需顯示占位背景圖片
-
自定義View優化。使用 canvas.clipRect() 幫助系統識別那些可見的區域,只有在這個區域內才會被繪製。
(3)啟動優化
應用一般都有閃屏頁SplashActivity,優化閃屏頁的 UI 佈局,可以通過 Profile GPU Rendering 檢測丟幀情況。
(另外,還可以IDE自帶的一款UI繪製檢測圖形化數據分析工具 Systrace ,4.0版本以上版本可以使用。)
閃屏頁的存在可以說就是啟動優化,通常在閃屏頁延遲2秒跳轉到主界面,但是在進入首頁的時候,首頁複雜的View渲染以及必須在UI線程執行的業務邏輯,必然拖慢了啟動速度。啟動閃屏頁雖然簡單執行快,首頁卻複雜執行慢,應用啟動前輕後重。
所以要啟動載入邏輯優化。可以採用分佈載入、非同步載入、延期載入策略來提高應用啟動速。例如,把SplashActivity改成SplashFragment,應用程式的入口變成MainActivity,在MainActivity中先展示SplashFragment,顯示完畢後再移除SplashFragment。這樣,在SplashFragment的2S的友好時間內進行數據準備的同時,首頁的View就能夠被載入,首頁的業務邏輯就能夠被執行。在閃屏頁視窗載入完畢後,我們載入activity_main的佈局,考慮到這個佈局有可能比較複雜,耽誤View的解析時間,可以採用ViewStub的形式進行懶載入。
(4)刷新優化
- 減少刷新次數;
- 縮小刷新區域;
(5)動畫優化
需要實現動畫效果時,需要根據不同場景選擇合適的動畫框架來實現。有些情況下,可以用硬體加速方式來提供流暢度降低動畫卡頓。
3.耗損(耗電、流量消耗)
3.1耗電優化
在移動設備中,電池的重要性自然不言而喻,如果手機沒電了應用功能技術實現再怎麼牛逼,用戶也什麼都幹不成。對於Android操作系統和設備各大開發商來說,對手機耗電的優化從沒有停止過,不斷地追求更長的待機時間。而對於開發一款應用來說,絕不可以忽略電量耗損的問題,被歸為“電池殺手”的應用,最終的結果無疑是走向被用戶卸載的道路。比如,有些應用為了保持應用進程長期在後臺存活,使用各種不合理進程保活方案,破壞操作系統“生態平衡”,導致用戶電量嚴重耗損,雖然這種流氓開發行為並不違法吧,但是也屬於不道德的行為,也同樣會被同行所被鄙視的行為。
在 Android5.0 以前,關於應用電量消耗的測試即麻煩又不准確,而5.0 之後Google專門引入了一個獲取設備上電量消耗信息的API—— Battery Historian。Battery Historian 是一款由 Google 提供的 Android 系統電量分析工具,直觀地展示出手機的電量消耗過程,通過輸入電量分析文件,顯示消耗情況。
最後提供一些可供參考耗電優化的方法: