Android 性能優化

上週四參加了MDCC大會的 Android,我比較關注的5R,做一個安靜的app,圖片緩存以及React Native For Android,其中很大一部分的內容都是講的性能優化,後續還會給大家帶來一篇React Native ,下面就來總結一下Android性能優化方面的內容!

人類大腦與眼睛對一個畫面的連貫性感知其實是有一個界限的,譬如我們看電影會覺得畫面很自然連貫(幀率爲24fps),用手機當然也需要感知屏幕操作的連貫性(尤其是動畫過度),所以Android索性就把達到這種流暢的幀率規定爲60fps(1000/60 = 16.67ms/幀), 所以在16ms內沒有把這一幀的任務完成,就會出現丟幀的情況,儘量保證每次在16ms內處理完所有的CPU與GPU計算、繪製、渲染等操作,否則會造成丟幀卡頓問題。

Reduce

  1. Cache/Drawable
  2. load in demand
  3. bitmap - scale/format

Reuse

  1. pools
  2. inBitmaps
  3. convertView
  4. onDraw / for

Recycle

  1. Inner class / container / static
  2. Context
  3. register/ungister
  4. bitmap/cursor/webview

Refactor

  1. arrayMap / no enum
  2. avoid memory fragment
  3. layout / overdraw

Revalue

  1. largeHeap
  2. multi - progress
  3. 3 - party libs

以上就是胡凱提出的5R原則,隨意感受一下,下面主要是從佈局優化,繪製優化,內存泄露優化,響應速度優化,ListView優化,Bitmap優化,線程優化等方面給出一些優化意見。

佈局優化

佈局優化的思想很簡單,儘量減少佈局的層級,佈局層級減少繪製時間就會跟着減少,從而提高性能

如何進行佈局優化呢?首先刪除佈局中的無用的控件和層級,其次有選擇的使用性能較低的viewgroup,不如佈局中即可以使用RelativeLayout也可以使用LinearLayout時,儘量選擇LinearLayout,相對來說RelativeLayout比較複雜一下,需要使用cpu的時間相對長一些,當出現多級嵌套時建議使用RelativeLayout,降低程序的性能

佈局優化的另一種方式就是使用 < include >(佈局重用),< merge >(降低層級),< viewstub >(按需加載)

可以通過SDK提供的工具HierarchyViewer來進行UI佈局複雜程度及冗餘等分析,具體如何操作,打開體驗一下就知道了。

繪製優化

繪製優化主要是避免view在onDraw方法中進行大量操作

  1. 不要在onDraw方法中創建局部對象,由於onDraw方法會頻繁調用,就要分配給它很多內存,會導致gc(虛擬機在執行GC垃圾回收操作時所有線程(包括UI線程)都需要暫停,當GC垃圾回收完成之後所有線程才能夠繼續執行),降低程序的執行效率
  2. 不要在onDraw方法中執行耗時操作,也不要執行循環操作,佔用cpu的時間過長,導致view繪製不流暢,耗時操作會引起ANR
  3. 背景和圖片等內存分配優化;儘量減少不必要的背景設置,圖片儘量壓縮處理顯示,儘量避免頻繁內存抖動等問題出現。

繪製UI可以通過開發者選項中的GPU過度繪製工具來進行分析。在設置->開發者選項->調試GPU過度繪製(不同設備可能位置或者叫法不同)中打開調試

內存泄露

衆所周知,在Java中有些對象的生命週期是有限的,當它們完成了特定的邏輯後將會被垃圾回收;但是,如果在對象的生命週期本來該被垃圾回收時這個對象還被別的對象所持有引用,那就會導致內存泄漏;這樣的後果就是隨着我們的應用被長時間使用,他所佔用的內存越來越大。

內存泄露可以引發很多的問題,常見的內存泄露導致問題如下:

  • 應用卡頓,響應速度慢(內存佔用高時JVM虛擬機會頻繁觸發GC)
  • 應用被從後臺進程幹爲空進程(上面系統內存原理有介紹,也就是超過了閾值)
  • 應用莫名的崩潰(上面應用內存原理有介紹,也就是超過了閾值OOM)

造成內存泄露泄露的最核心原理就是一個對象持有了超過自己生命週期以外的對象強引用導致該對象無法被正常垃圾回收;可以發現,應用內存泄露是個相當棘手重要的問題,我們必須重視。

內存泄露的優化方案有兩個

  1. 開發過程中避免寫出內存泄露的代碼
  2. 使用工具檢測內存泄露的方法,推薦簡單粗暴的LeakCanary

ListView優化

  1. 採用ViewHolder並避免在getView中執行耗時操作
  2. 根據列表的滑動狀態控制任務的執行頻率
  3. 嘗試開始硬件加速使ListView滑動過程更流暢

Bitmap優化

對於bitmap這個胖子操作它時,要特別注意一下,使用之前先判斷大小,通過BItmapFactory.Options來採樣,如果想當然的就是用了,oom就會找上門。

線程優化

線程優化的思想就是採用線程池,避免程序中出現大量的thread,線程池可以重用內部的線程,從而避免了線程的創建和銷燬所帶來的性能開銷,同時線程池還能更有效控制線程池的最大併發數,避免大量的線程因互相搶佔系統資源從而導致阻塞現象的發生。

性能優化建議

  1. 正確使用Context
  2. 使用Android提倡的方法,如 arrayMap
  3. 減少枚舉類型的使用,佔用內存相對來說比較大一些
  4. 合理使用largeHeap
  5. 慎重使用多進程,很多時候多進程缺點遠大於優點
  6. 慎重使用第三方jar包
  7. 對象的註冊與反註冊沒有成對出現造成的內存泄露;譬如註冊廣播接收器、註冊觀察者(典型的譬如數據庫的監聽)等。
  8. 創建與關閉沒有成對出現造成的泄露;譬如Cursor資源必須手動關閉,WebView必須手動銷燬,流等對象必須手動關閉等。

因爲Context的引用超過它本身的生命週期,會導致Context泄漏。所以儘量使用Application這種Context類型。 你可以通過調用Context.getApplicationContext()或 Activity.getApplication()輕鬆得到Application對象。

我們在應用中很多時候想當然的使用hashMap,其實Android 提供了它自己專用的arrayMap,SparseArray,Android提供這幾個方法也是有原因的,其內部實現了壓縮算法,減少存儲控件,節約內存,還有就是查找速度更快,使用二分法查找

當你的程序申請更多內容時,雖說看上去是個不錯的方法,但是你內存佔用很高的情況下會被優先被殺死,所以合理使用largeHeap

除了webview選擇單獨的進程之外的慎重考慮使用多進程,即使這個進程什麼都不做的情況下,也消耗不小的內存

第三方jar包,在不瞭解原理,內存佔用的情況下慎用,裏面可能存在很多你不瞭解的坑等着你去跳

對於內存優化這個話題,每個人都有自己的理解,歡迎批評指正,關於更多性能優化的問題請參考任玉剛的《Android 開發藝術探索》第15章

                                                杏樹林研發 郭莉莉
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章