Android性能優化總結

本文大體分為四部分
  1. 內存優化
  2. 布局優化
  3. 編碼優化
  4. 網絡優化

內存優化

主要參考胡凱文章

首先說一下內存泄漏和OOM:
  1. 內存泄漏,因為不恰當的引用導致本該被釋放的資源無法得到釋放。
  2. OOM,新分配的內存大小加上已經占用的內存大小,超出了限制的內存大小。

內存泄漏更多是因為我們的代碼寫的有問題,OOM更多是因為我們對我們應用內存的占用沒有很好的把控。內存泄漏是導致OOM的一大元兇。

內存優化分為5點來說:
  1. 減少對象內存占用
  2. 內存對象的復用
  3. 避免內存泄漏
  4. 合理的內存使用策略
  5. 內存優化輔助工具

一、減少對象內存占用

  1. 使用更加輕量的數據結構。比如:ArrayMap/SparseArray是替代HashMap的好幫手。關于ArrayMap和SparseArray的使用:
  • 適合對象個數的數量級最好在千以內,因為他們的插入和刪除的效率不夠高。
  • 查找和插入使用的是二分查找。
  • key類型是int時,請使用SparseArray因為它避免了自動裝箱。
  1. 避免使用Enum。官方說法是,相對于靜態常量,枚舉會消耗兩倍以上的內存。并且在運行時還會產生額外的內存占用。在一個官方實例里,枚舉占用的內存是靜態常量的13倍,運行時內存占用是6倍。
  2. 減少Bitmap對象的內存占用。對于創建出來的Bitmap對象通常有兩個操作可以優化其內存占用。
  • inSampleSize:在載入內存之前,計算一個合適的縮放比例。
  • decode format:解碼格式,ARGB_8888(每個像素4個字節,最高精度,有透明通道)、RGB_565(每個像素兩個字節,無透明度)、ARGB_4444(deprecated in Api13)、Alpah_8,不同的解碼格式差別很大。根據情況選擇合適的會比較好。
  1. 使用更小的圖片。拿到美工給的圖,要留意大圖直接被XML引用有時會出現InflationException,該異常的根本原因就是OOM。

二、內存對象的復用

  1. 復用系統自帶的資源。系統自帶了很多顏色、動畫、樣式、布局、圖片。使用這些可以減少內存開銷,但需注意版本差異性。
  2. ListView/GridView/RecyclerView內重復子View的復用。
  3. Bitmap對象復用。使用inBitmap來復用已經存在的內存區域。3.0之后出現,重用的bitmap大小和解碼格式需要一致。4.4以后優化大小限制,只要小于或等于原bitmap的大小即可??梢跃S護一個有多種典型bitmap的對象池,使得后續bitmap創建都可以找到合適的復用模板。
  4. 在頻繁調用的方法外創建對象。如onDraw()方法會頻繁調用,在里面做創建對象的操作會迅速增加內存使用,很容易引起頻繁GC甚至是內存抖動。
  5. StringBuilder/StringBuffer。使用StringBuilder/StringBuffer來替代頻繁的字符串拼接操作。

三、避免內存泄漏

  1. Activity的泄漏。
  • 內部類引用導致。典型的如Handler??紤]盡量使用靜態內部類,同時使用弱引用機制避免互相引用出現的泄漏。
  • Activity Context被傳遞到其他實例中,可能導致自身被引用發生泄漏。盡量使用Application Context。除了和UI相關的,如顯示彈窗、啟動Activity、填充布局。參考Android Context。
  1. 臨時Bitmap對象的回收。臨時創建一個相對比較大的bitmap對象,在經過變換獲得新的bitmap對象之后,應盡快回收之前的bitmap。注意createBitmap()方法可能返回source bitmap,所以需要檢查返回值是否和source bitmap相等。不等才可以對source bitmap執行recycle方法。
  2. 監聽器的注銷。
  3. Cursor對象的及時關閉。
  4. 緩存容器的對象泄漏。如4.0之前,把drawable添加到緩存容器,因為drawable和view的強引用很容易導致activity發生泄漏。
  5. WebView的泄露。Android的WebView存在很大的兼容性問題,WebView因為不同系統版本不同廠商都粗乃很大的差異,甚至標準的WebView存在內存泄漏的問題(09年發現,13年修復)。根治方法:為WebView使用新進程,通過AIDL進行通信,WebView所在進程根據業務需要在合適時機進行銷毀。
  6. 慎用static對象,static的生命周期和應用的進程保持一致,使用不當很可能導致內存泄漏。
  7. 留意單例對象中不合理的引用。單例對象的生命周期和應用保持一致。

四、合理的內存使用策略

  1. 使用IntentService代替Service。
  2. 謹慎使用large heap。在清單文件的<application>節點設置largeHeap=true可以為應用生命一個更大的heap控件。會影響用戶體驗,并使GC運行時間更長,任務切換耗能增加。并且,在一些嚴格限制的機器上,largeHeap和通常的heap size大小一樣。你始終應該通過getMemoryClass()來檢查實際獲取到的heap大小。
  3. 合適的緩存大小。結合可用內存大小等因素設置。
  4. onLowMemory()和onTrimMemory()。后者從4.0開始提供,提供了更為詳細的系統內存占用級別??梢酝ㄟ^監測系統內存占用適當的釋放自身的一些內存占用。
  5. 選擇合適的文件夾存放資源文件。圖片會被拉伸以適應不同的設備。對于不希望被拉伸的圖片,放在assets或nodpi目錄下。
  6. 對大內存分配做Try...Catch...操作。比如給解析大圖時,使用try catch,catch到OOM后將采樣比例增加一倍再次嘗試解析。
  7. 慎用抽象編程。抽象需要同等量的代碼用于可執行,這些代碼會被mapping到內存中。
  8. 使用nano protobufs序列化數據。Google設計,類似XML,比XML更加輕量快速簡單。
  9. 慎用依賴注入。通過掃描你的代碼執行許多初始化操作,會導致你的代碼需要大量的內存空間來mapping代碼,而且mapped pages會長時間保留在內存中。
  10. 慎用多進程??梢詳U大應用的內存占用范圍,但使用不當會導致顯著增加內存。
  11. 使用ProGuard剔除不需要的代碼。
  12. 慎用第三方庫。很多功能會用不上。

五、內存優化輔助工具

  1. facebook開源的LeakCanary,可用來監測內存泄漏
  2. Android Monitor,可以查看內存占用,可以查看指向,可以手動觸發GC。分析內存泄漏的流程是
  3. 手動觸發GC
  4. 查看JavaHeap
  5. 點擊Analyzer Task即可進行內存泄漏的分析。

布局優化

分四個方面

  1. 選擇合適的根節點
  2. 重用布局文件
  3. 僅在需要時加載布局
  4. 避免過度繪制

一、選擇合適的根節點

Android在創建Activity時默認生成的布局為RelativeLayout,而新建布局時默認的根節點為LinearLayout。這是因為

  1. 在復雜的布局中使用RelativeLayout可以降低布局嵌套,使布局比較扁平。也更加靈活。
  2. 對于簡單的布局,LinearLayout在不用處理weight屬性的情況下,性能上是優于至少需要計算兩次的RelativeLayout的。

二、重用布局文件

  1. <include>標簽的使用,要注意如果需要使用layout屬性,必需先設置layout:width和layout:height
  2. <merge>標簽的使用可減少不必要的視圖嵌套 :
  3. 添加的子視圖不需要針對父視圖的屬性,只是要添加到父視圖上顯示。根節點可為<merge>。
  4. 比如在LinearLayout里include另外一個方向相同的LinearLayout,這個被include的視圖的根節點就可以改為merge.

三、僅在需要時加載布局

<ViewStub>
使用時調用inflate即可,也可以調用setVisibility(View.VISIBILITY)。
注意:不支持<merge>標簽的布局。

四、避免過度繪制

比如給根布局設置了圖片背景,但是用戶只能看到子View,根本就沒有看到最下面的背景。但是背景仍要被繪制。這就是過度繪制。
可以通過設置-開發者選項-顯示GPU過度繪制來觀察過度繪制。顏色越深的區域過度繪制越嚴重,藍色最好,紅色最差。

  1. 去除不必要的背景設置。
  2. 自定義view時,通過Canvas的clipRect()來繪制部分需要重繪的區域。

五、小知識點

  • android:drawableXXX屬性。TextView控件可直接顯示圖片和文字。
  • setCompoundDrawable(),代碼中通過該方法實現第一個效果。
  • android:divider,使用自帶的分割線。
  • space控件,可用于添加空白間隔,該控件不進行繪制。
  • android:lineSpacingExtra="",android:text="aaa\nbbb\nccc"多行文字可使用TextView的行間距實現。
  • Spannable,使用Spannable來為TextView設置強大的樣式。

編碼優化

幾個點

  1. 靜態方法。將一項通用的功能寫成靜態方法,調用速度會提升15%-20%,同時不需要創建對象來調用該方法,也不用擔心改變對象的狀態(靜態方法無法訪問非靜態字段)。
  2. 避免創建不必要的對象
  3. 靜態最終常量。對基本數據類型以及String常量使用static final修飾,會在dex文件的初始化器中進行初始化,會更快。
  4. 多使用增強型for循環,但ArrayList使用傳統循環方式。
  5. 使用系統封裝好的API。系統的API很多功能是通過底層匯編模式執行的,效率會比較高。如數組拷貝的功能,使用System.arrayCopy()會比使用循環一一賦值效率高9倍以上。
  6. 避免在內部使用getter/setter。內部使用時,字段查找比方法調用效率高。

網絡優化

工具:Android Studio有Network Monitor

主要有:

  1. 接口設置多樣化,便于App可以以較少的請求來完成業務需求。
  2. 使用Gzip壓縮request和response,減少數據傳輸大小
  3. 可以使用Protocol Buffer來代替json、XML等
  4. 合適的圖片。獲取圖片時告知服務器寬高質量等來獲取合適的圖片資源。
  5. 設置網絡緩存,來取消不必要的網絡請求。
  6. 在網絡良好的時候,對一些很有可能會進行操作的數據進行提前獲取。
  7. 弱網優化,Android Emulator可以設置網絡速度和延遲來做弱網測試。可采取的措施如:不自動加載圖片、先反饋后提交(如用戶點贊,先給提交成功的反饋,記錄下來之后提交)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容