huazi

huazi

Android 性能優化總結

Android 設備作為移動設備,不管是內存還是 CPU 的性能都受到了一定的限制。鑒於此,Android 不能無限制的使用內存和 CPU 資源,過多的使用內存會導致內存溢出,即 OOM。而過多的使用 CPU 資源,會導致手機變得卡頓,甚至出現程序無響應的情況,即 ANR。因此,Android 程序的性能問題變得異常突出。這也要求我們再平常的編碼中注意性能優化。而優化的前提是能明確的知道那種情況會導致性能出現問題。下面就總結一下性能優化的一些方法。

1. 布局優化#

優化布局的思想很簡單,就是儘量減少布局文件的層級,布局層間減少,意味著繪製工作量減少。如果進行布局優化?

  • 首先刪除布局中無用的控件和層級,其次有選擇的使用 ViewGroup, 比如 LinearLayout 和 RelativeLayout 都可以實現,那麼就選用 LinearLayout, 因為 RelativeLayout 功能複雜,他的布局過程花費更多的 CPU 時間。另外,減少嵌套是經常用也是最直觀的方式。

  • 採用 <include> 標籤, <merge> 標籤和ViewStub<include> 標籤主要用於布局重用,<merge> 標籤用於減少嵌套,可以配合<include> 標籤一起使用或者在自定義 View 時使用。ViewStub 則提供了按需加載的功能,它非常輕量級,寬高都是 0,因此本身不參與布局和繪製,很多布局在正常情況下不會顯示,在特定場景下顯示,因此只需要到該顯示的時候再加載就好,可以提高初始化的性能。

2. 繪製優化#

繪製優化是指 View 的 onDraw 方法避免執行大量的操作,主要體現在兩個方面。

  • 首先,onDraw 不要創建新的局部對象,因為 onDraw 會頻繁的調用,這樣會瞬間產生大量的臨時對象,這不僅佔用過多的內存,而且會導致頻繁的 GC,降低了程序執行的效率。

  • 其次,onDraw 方法中不要做耗時任務,也不能執行大量的循環操作,儘管每次循環都很輕量級,但大量的循環仍然十分搶占 CPU 的時間片,這會造成 View 繪製過程不流暢。谷歌官方性能優化標準,View 的繪製幀率保持在 60fps 是最佳的,這就要求每幀的繪製時間不超過 16ms (16ms = 1000/60)。

3. 內存泄漏優化#

內存泄漏對開發人員的經驗和開發意識要求較高,因此也是最容易犯的錯誤之一。內存泄漏的優化主要有兩個方面,一方面就是開發中避免寫出有內存泄漏的代碼,另一方面是通過一些分析工具找出潛在的內存泄漏而解決。列舉一些容易出現內存泄漏的編碼情況:

  • 靜態變量導致內存泄漏

    比如 Context, View 為靜態變量,它內部持有了 Activity,所以當 Activity 關閉後仍然無法釋放。

  • 單例模式導致內存泄漏

    比較明顯的是同上,直接引用對象持有了 Activity,導致無法釋放。另一種不太明顯的是註冊監聽方式,只註冊,而缺少取消註冊的情況也會引起內存泄漏。因為單例的特點是其生命周期和 Applation 保持一致,因此會導致內存泄漏。

  • 屬性動畫導致內存泄漏

    屬性動畫是一類無限循環的動畫,如果在 Activity 中播放此類動畫且沒有在 onDestory 中停止,那麼動畫就會一直播放下去,因為 Activity 會被動畫 View 持有,最終 Activity 無法釋放。解決方法就是及時停止動畫。

至於分析內存泄漏的工具有很多,比如:

  • Android Studio 自帶的 Profiler

    可以直觀的看到 CPU,內存,網絡變化,也可以做很多模擬操作,但是不太容易看出內存泄漏,需要配合 MTA 使用。

  • MAT

    MAT 全稱 Eclipse Memory Analyzer,是一款強大的內存泄漏分析工具。

  • Android LeakCanary

    Android LeakCanary 易於集成,自動檢測出內存泄漏,十分好用。目前我們項目中也是用的 LeakCanary。使用方法可以去參考文檔。

上面這些工具只是幫助我們分析和定位內存泄漏的位置,等知道問題出在哪了,才能去解決問題。

4. 響應速度優化#

核心思想就是避免在主線程中做耗時操作,當有耗時操作時應當放在子線程中去操作。響應速度過慢一般體現在 Activity 啟動速度上面,主線程做太多事情,會導致黑屏甚至出現 ANR。

  • 耗時操作放在子線程
  • 業務優化,比如采用新算法,代碼重構,償還歷史債務等
  • 通過分析 trace.txt 文件定位 ANR 的原因
  • 主線程和子線程搶占同步鎖,子線程持有了主線程所需的鎖

5. RecyclerView 和 Bitmap 優化#

  • 避免再 onBindView 中執行耗時操作
  • 根據列表的滑動狀態來控制任務的執行頻率,比如當列表快速滑動時不適合開啟大量的異步任務
  • 對於 Bitmap 主要通過 BitmapFactory.Options 來根據需要對圖片進行採樣,加載合適大小的圖片,降低 Bitmap 的大小

6. 線程優化#

線程優化主要是采用線程池,避免程序中存在大量的 Thread,線程池可以重用內部的線程,從而避免了線程的創建和銷毀代碼的性能開銷,同時線程池還能有效的控制線程中的最大並發數,避免大量的線程因互相搶占資源而導致阻塞現象的發生。因此開發過程中盡量使用線程池,而不是每次都要創建一個 Thread。

7. 優化建議#

  • 盡量避免創建過多對象
  • 不要過多使用枚舉,枚舉佔用的內存空間比整型大
  • 常量使用 static final 來修飾
  • 使用一些 Android 特有的數據結構,他們有更好的性能
  • 適當使用軟引用,弱引用
  • 採用內存緩存和磁盤緩存
  • 盡量采用靜態內部類,這樣避免潛在的由於內部類導致內存泄漏
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。