Android應用優化小手冊

對我們技術從業者而言,很多時候時候不是我們不知道怎麼做,而是不知道做什麼?今天系統的總結自己關於如何對Android應用進行優化的一些經驗,共計八個維度。僅供拋磚引玉,不足的地方,還請大家補充,謝謝!!!

1.布局優化

為什麼?

Android系統每個16ms發出VSYNC信號,觸發對UI的渲染,要想達到界面流暢,必須實現60fps,也就意味著大多數的操作必須在16ms完成.

除了上面界面過於複雜導致渲染不能及時完成之外,還存在過度繪製問題.所謂過度繪製就是某個像素在同一幀的時間內被繪製多次.在多層次的UI界面中,如果不可見的UI也在進行繪製,那麼這些重合區域的像素就會被繪製多次,從而浪費大量的CPU和GPU資源.過度繪製也發生在背景重疊的情況下,比如Layout中有自己的背景,同時子View中又有自己的背景.

Advertisements

如何檢測?

使用HierarchyViewer來查找Activity中的布局是否過於複雜

在開發者選項中打開Show GPU Overdraw選項進行觀察是否存在過度繪製

在開發者選項中選擇Profile GPU Rendering,選中On screen as bar

使用TraceView來觀察CPU執行情況

如何優化?

減少布局的層級,合理的使用include,merge,ViewStub

自定義組件的onDraw()中避免大量創建臨時對象,比如String,以免頻繁觸發GC

自定義組件的onDraw()中,考慮使用canvas.clipRect()繪製需要被繪製的區域

對像ListView這樣的組件容器,考慮使用convertView,使用ViewHolder,

Advertisements

考慮使用性能更高的組件,比如推薦使用RecycleView來代替ListView,使用staticlayout來實現自動換行

2.內存優化

為什麼?

資源總是有限的,內存同樣也是一種資源.在Android當中,過度的/不恰當佔用內存資源,會導致應用頻繁被殺死,最終也會影響用戶的整體體驗.任何一名開發者,都應該將節省內存牢記心中.

如何檢測?

使用LeakCanary

使用MAT分析Java堆

使用Android Device Monitor中的Application Tracker追蹤內存分配信息

Android Studio中的Android Monitor,選擇其中的Memory

如何優化?

主動的釋放內存,在onLowMemory()和onTrimMemory()中適當的釋放內存

避免內存泄漏和內存溢出

在使用Bitmap的時候,考慮對其進行壓縮,使用緩存或者改變顏色模式,比如android默認的顏色格式是ARGB_8888,在要求不高的情況下可以採用RGB__565,這樣每個像素1佔用的內存就可懂4byte到2byte.

減少幀動畫的使用,如果需要,通過SurfaceView實現

使用更輕量級的數據結構,比如ArrayMap/SparseArray

合理的使用相關組件,比如Service和Webview,在不需要的時候主動結束其生命周期

合理的使用多進程,比如像音樂播放器類,可以分為主進程和播放進程

使用非同步隊列時考慮有界隊列

如果你能明確知道HashMap的大小,那就再初始化時為其制定容量

3.電量優化

為什麼?

電量是移動設備非常寶貴的資源,作為一名開發者,有必要為用戶著想,減少電量的消耗.調查顯示通常只有30%左右的電量是被程序核心的功能所消耗,比如界面渲染,剩下的70%則是被上報數據,位置更新,後台通知所消耗.

如何檢測?

手機選項中通過查看APP的電量消耗的統計數據

使用Battery Historian Tool來查看詳細的電量消耗

如何優化?

減少喚醒屏幕的次數與持續的時間,正確的使用WakeLock.

延遲非必須的操作到充電狀態時,比如日誌上報完全可以在夜間充電時完成,這點可以結合JobScheduler使用

使用感測器採集數據時,一旦不需要記得取消註冊.

減少網路通信,合併通信.

合理使用定位功能,減少位置更新頻率以及根據實際情況使用不同精度的定位需求

4.網路優化

為什麼?

現在App幾乎都需要聯網操作,做好網路優化一方面可以提高體驗,另一方面可以減少流量和電量的損耗.另外,無論是對用戶還是網路服務提供者,網路同樣是一種資源,任何開發者都不應該假設網路資源是無限制的.

如何檢測?

使用Android Studio里的Network Traffic Tools來查看網路請求

使用Android Studio中的Monitor

使用Fidder或者Charles等抓包工具分析網路數據包

如何優化?

有必要的時候務必做好緩存,無論是圖片還是普通的數據,使用LruCache和DiskLruCache構建自己的緩存系統,並根據實際場景設計緩存策略

避免過度的網路同步,合併相關的網路請求

根據實際場景確定請求策略,避免使用固定的間隔頻率來進行網路操作.比如連接WiFi並充電的情況下請求頻率可以高,第一次網路請求失敗后可以使用雙倍的時間間隔來進行下一次

減少數據傳輸量,對傳輸的數據做壓縮.如果傳輸的是圖片,需要選擇合適的圖片格式以及根據顯示大小請求合適規格的圖片.對於普通數據,可以考慮使用ProtocalBuffers來減小傳輸數據的大小.

某些情況下可以採用IP直連,一方面可以減少DNS解析時間,另一方面可以防止域名劫持

5.啟動優化

為什麼?

啟動優化看起來並不是那麼必要,但從心理學角度而言,越快的啟動速度往往給用戶以性能好,高效可靠的心理暗示,這就很容易讓用戶對其產生好感,為你後面打動用戶留下了餘地.

如何檢測?

使用Method Tracing

使用Systrace,比如在onCreate中添加trace.beginSection()和trace.endSection()

使用adb shell am start -W [packageName]/[packageName.MainActivity]測量冷啟動時間

如何優化?

Activity的onCreate()中減少複雜和耗時的操作

Application的onCreate(),attachBaseContext()中同樣減少複雜和耗時的操作,但是對於很多App在此處會執行大量組件和服務的初始化操作,如果可能考慮并行初始化

提供自定義啟動窗口,比如將一張圖片通過設置主題的方式顯示為啟動窗口.

優化布局

6.體積優化

為什麼?

對用戶而言,無論是用戶空間還是網路,亦或是時間,都是資源.體積優化就是為用戶節省資源的重要一環.如果你現在做的是SDK類產品,那麼體積優化同樣重要.

如何檢測?

使用Android Lint檢查沒有使用的資源

如何優化?

減少不必要的依賴庫/Jar,在滿足需求的前提下優先選擇體積小的.

使用Proguard工具進行代碼瘦身,優化,混淆

減少so文件的數量,根據實際情況提供so文件

使用Gradle中的shrinkResource來將無用的代碼和資源排除在APK安裝包之外

減少圖片資源的大小,考慮圖片壓縮或者使用Vertor Drawable替代png/jpeg

有選擇的提供對應解析度的圖片資源

復用已經存在的圖片,多用通過代碼對已有圖片進行變換的方式實現復用

使用插件化技術(如果項目簡單就不要使用)

7.性能優化

能發揮出100%的能力就不要只發揮其中的50%,這對應用而言並非壞事.同樣的價格賣給用戶兩輛車,我想大多數人會選擇性能更好的.

如何檢測?

使用Lint執行靜態分析,在Android Studio的Analysis->Inspect Code

在開發者選項中開啟StrictMode或者在代碼中開啟

代碼Review

如何優化?

任務并行化,對可能的任務進行并行操作,多藉助線程池而非直接使用線程

如何需要序列化數據,優先考慮Android自身提供的而非Java提供的Serializable

選擇合適的數據結構,明確List/Set/Map/Stack操作的複雜度

使用Android提供更高效的容器,比如使用ArrayMap來代替HashMap,此外還是有SparseBoolMap,SparseIntMap,SparseLongMap

使用靜態常量代替Enum類型,可以減少至少兩倍的內存消耗

使用對象池技術,比如提供想String一樣的對象池

使用緩存技術

字元串拼接操作有限使用StringBuilder

對相關的演算法和邏輯進行優化,減少不必要的流程

採用JNI,對計算量較大的邏輯將其協程so文件,如圖片處理

業務優化

除了上述比較通用的優化方案之外,也應該花點時間放在業務優化上.很多時候,迫於時間壓迫,當前實現業務的方案並非最優.比如為了支持多張圖片上傳,很多人直接使用串列操作,儘管這樣做容易實現,但是卻並非最佳.

由於每個產品的業務並不相同,也就很難有通用的優化方案,這裡又兩個目標值得思考:

如果有可能,串列業務并行化

如果有可能,簡化業務流程.將一大象關進冰箱的方法就是打開冰箱,將大象放進去,最後關閉冰箱.

之所以把業務優化放在最後的根本原因是業務優化的風險較高,需要團隊的整體配合來完成.

Android中圖片有四種顏色格式,分別是

默認的是ARGB_8888,其中ARGB分別代表的是透明度,紅色,綠色,藍色,每個值分別用8位來記錄,也就是一個像素會佔用4byte,共32位.

而ARGB_4444和以上很類似,但是每個值分別用4位來記錄,也就是一個像素會佔用2byte,共16位.

RGB_565則分別用5位,6位,5位來記錄每個值,不存在透明度,每個像素會佔用2byte,共16位.

ALPHA_8:該像素只保存透明度,會佔用1byte,共8位.

在實際應用中而言,值推薦使用ARGB_8888以及RGB_565,如果你不需要透明度,那麼就選擇RGB_565,可以減少一半的內存佔用. ↩

Android中圖片有四種顏色格式,分別是

默認的是ARGB_8888,其中ARGB分別代表的是透明度,紅色,綠色,藍色,每個值分別用8位來記錄,也就是一個像素會佔用4byte,共32位.

而ARGB_4444和以上很類似,但是每個值分別用4位來記錄,也就是一個像素會佔用2byte,共16位.

RGB_565則分別用5位,6位,5位來記錄每個值,不存在透明度,每個像素會佔用2byte,共16位.

ALPHA_8:該像素只保存透明度,會佔用1byte,共8位.

在實際應用中而言,值推薦使用ARGB_8888以及RGB_565,如果你不需要透明度,那麼就選擇RGB_565,可以減少一半的內存佔用.

Advertisements

你可能會喜歡