標籤:android 效能最佳化
上周四參加了MDCC大會的 Android,我比較關注的5R,做一個安靜的app,圖片緩衝以及React Native For Android,其中很大一部分的內容都是講的效能最佳化,後續還會給大家帶來一篇React Native ,下面就來總結一下Android效能最佳化方面的內容!
Reduce
- Cache/Drawable
- load in demand
- bitmap - scale/format
Reuse
- pools
- inBitmaps
- convertView
- onDraw / for
Recycle
- Inner class / container / static
- Context
- register/ungister
- bitmap/cursor/webview
Refactor
- arrayMap / no enum
- avoid memory fragment
- layout / overdraw
Revalue
- largeHeap
- multi - progress
- 3 - party libs
以上就是胡凱提出的5R原則,隨意感受一下,下面主要是從布局最佳化,繪製最佳化,記憶體泄露最佳化,響應速度最佳化,ListView最佳化,Bitmap最佳化,線程最佳化等方面給出一些最佳化意見。
布局最佳化
布局最佳化的思想很簡單,盡量減少布局的層級,布局層級減少繪製時間就會跟著減少,從而提高效能
如何進行布局最佳化呢?首先刪除布局中的無用的控制項和層級,其次有選擇的使用效能較低的viewgroup,不如布局中即可以使用RelativeLayout也可以使用LinearLayout時,盡量選擇LinearLayout,相對來說RelativeLayout比較複雜一下,需要使用cpu的時間相對長一些,當出現多級嵌套時建議使用RelativeLayout,降低程式的效能
布局最佳化的另一種方式就是使用 < include >(布局重用)< merge >(降低層級)< viewstub >(按需載入)
可以通過SDK提供的工具HierarchyViewer來進行UI布局複雜程度及冗餘等分析,具體如何操作,開啟體驗一下就知道了。
繪製最佳化
人類大腦與眼睛對一個畫面的連貫性感知其實是有一個界限的,譬如我們看電影會覺得畫面很自然連貫(幀率為24fps),用手機當然也需要感知螢幕操作的連貫性(尤其是動畫過度),所以Android索性就把達到這種流暢的幀率規定為60fps(1000/60 = 16.67ms/幀), 所以在16ms內沒有把這一幀的任務完成,就會出現丟幀的情況,盡量保證每次在16ms內處理完所有的CPU與GPU計算、繪製、渲染等操作,否則會造成丟幀卡頓問題。
繪製最佳化主要是避免view在onDraw方法中進行大量操作
- 不要在onDraw方法中建立局部對象,由於onDraw方法會頻繁調用,就要分配給它很多記憶體,會導致gc(虛擬機器在執行GC記憶體回收操作時所有線程(包括UI線程)都需要暫停,當GC記憶體回收完成之後所有線程才能夠繼續執行),降低程式的執行效率
- 不要在onDraw方法中執行耗時操作,也不要執行迴圈操作,佔用cpu的時間過長,導致view繪製不流暢,耗時操作會引起ANR
- 背景和圖片等記憶體配置最佳化;盡量減少不必要的背景設定,圖片盡量壓縮處理顯示,盡量避免頻繁記憶體抖動等問題出現。
繪製UI可以通過開發人員選項中的GPU過度繪製工具來進行分析。在設定->開發人員選項->調試GPU過度繪製(不同裝置可能位置或者叫法不同)中開啟調試
記憶體泄露
眾所周知,在Java中有些對象的生命週期是有限的,當它們完成了特定的邏輯後將會被記憶體回收;但是,如果在對象的生命週期本來該被記憶體回收時這個對象還被別的對象所持有引用,那就會導致記憶體流失;這樣的後果就是隨著我們的應用被長時間使用,他所佔用的記憶體越來越大。
記憶體泄露可以引發很多的問題,常見的記憶體泄露導致問題如下:
- 應用卡頓,響應速度慢(記憶體佔用高時JVM虛擬機器會頻繁觸發GC)
- 應用被從後台進程幹為空白進程(上面系統記憶體原理有介紹,也就是超過了閾值)
- 應用莫名的崩潰(上面應用記憶體原理有介紹,也就是超過了閾值OOM)
造成記憶體泄露泄露的最核心原理就是一個對象持有了超過自己生命週期以外的對象強引用導致該對象無法被正常記憶體回收;可以發現,應用記憶體泄露是個相當棘手重要的問題,我們必須重視。
記憶體泄露的最佳化方案有兩個
- 開發過程中避免寫出記憶體泄露的代碼
- 使用工具檢測記憶體泄露的方法,推薦簡單粗暴的LeakCanary
ListView最佳化
- 採用ViewHolder並避免在getView中執行耗時操作
- 根據列表的滑動狀態控制任務的執行頻率
- 嘗試開始硬體加速使ListView滑動過程更流暢
Bitmap最佳化
對於bitmap這個胖子操作它時,要特別注意一下,使用之前先判斷大小,通過BItmapFactory.Options來採樣,如果想當然的就是用了,oom就會找上門。
線程最佳化
線程最佳化的思想就是採用線程池,避免程式中出現大量的thread,線程池可以重用內部的線程,從而避免了線程的建立和銷毀所帶來的效能開銷,同時線程池還能更有效控制線程池的最大並發數,避免大量的線程因互相搶佔系統資源從而導致阻塞現象的發生。
效能最佳化建議
- 正確使用Context,因為Context的引用超過它本身的生命週期,會導致Context泄漏。所以盡量使用Application這種Context類型。 你可以通過調用Context.getApplicationContext()或 Activity.getApplication()輕鬆得到Application對象。
- 使用Android提倡的方法,我們在應用中很多時候想當然的使用hashMap,其實Android 提供了它自己專用的arrayMap,SparseArray,Android提供這幾個方法也是有原因的,其內部實現了壓縮演算法,減少儲存控制項,節約記憶體,還有就是尋找速度更快,使用二分法尋找
- 減少枚舉類型的使用,佔用記憶體相對來說比較大一些
- 合理使用largeHeap,當你的程式申請更多內容時,雖說看上去是個不錯的方法,但是你記憶體佔用很高的情況下會被優先被殺死,所以合理使用largeHeap
- 謹慎使用多進程,很多時候多進程缺點遠大於優點,除了webview選擇單獨的進程之外的謹慎考慮使用多進程,即使這個進程什麼都不做的情況下,也消耗不小的記憶體
- 謹慎使用第三方jar包,第三方jar包,在不瞭解原理,記憶體佔用的情況下慎用,裡面可能存在很多你不瞭解的坑等著你去跳
- 對象的註冊與反註冊沒有成對出現造成的記憶體泄露;譬如註冊廣播接收器、註冊觀察者(典型的譬如資料庫的監聽)等。
- 建立與關閉沒有成對出現造成的泄露;譬如Cursor資源必須手動關閉,WebView必須手動銷毀,流等對象必須手動關閉等。
對於記憶體最佳化這個話題,每個人都有自己的理解,歡迎批評指正,關於記憶體最佳化的更多內容請參考任玉剛的《Android 開發藝術探索》第15章
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Android 效能最佳化