Android開發優化寶典

I. 網絡相關

  • http頭信息帶Cache-Control域 肯定緩存過時時間 防止重複請求
  • 直接用IP直連,不用域名,策略性跟新本地IP列表。 – DNS解析過程耗時在百毫秒左右,而且還有可能存在DNS劫持。
  • 圖片、JS、CSS等靜態資源,採用CDN(固然若是是使用7牛之類的服務就已經給你搭建佈置好了)
  • 全局圖片處理採用漏斗模型全局管控,所請求的圖片大小最好依照業務大小提供/最大不超過屏幕分辨率須要,若是請求原圖,也不要超過GL10.GL_MAX_TEXTURE_SIZE
  • 全局縮略圖直接採用webp,在儘量不損失圖片質量的前提下,圖片大小與png比縮小30% ~ 70%
  • 若是列表裏的縮略圖服務器處理好的小圖,能夠考慮直接在列表數據請求中,直接以base64在列表數據中直接帶上圖片(國內還比較少,海外有些這種作法,好像web端比較常見)
  • 輪詢或者socket心跳採用系統AlarmManager提供的鬧鐘服務來作,保證在系統休眠的時候cpu能夠獲得休眠,在須要喚醒時能夠喚醒(持有cpu喚醒鎖)
  • 能夠經過將零散的網路的請求打包進行一次操做,避免過多的無線信號引發電量消耗。

1. 傳輸數據格式選擇

  • 若是是基本須要全量數據的,考慮使用Protobuffers (序列化反序列化性能高於json)
  • 若是傳輸回來的數據不須要全量讀取,考慮使用Flatbuffers (序列化反序列化幾乎不耗時,耗時是在讀取對象時(就這一部分若是須要優化,能夠參看Flatbuffer Use Optimize

2. 輸入流

使用具備緩存策略的輸入流html

建議替換爲
InputStream BufferedInputStream
Reader BufferedReader

II. 數據結構

若是已知大概須要多大,就直接給初始大小,減小擴容時額外開銷。android

1. List

ArrayList

裏面就一數組,內存小,有序取值快,擴容效率低git

LinkedList

裏面就一雙向鏈表,內存大,隨機插入刪除快,擴容效率高。github

2. Hash

HashSet

裏面就一個HashMap,用key對外存儲,目的就是不容許重複元素。web

ConcurrentHashMap

線程安全,採用細分鎖,鎖顆粒更小,併發性能更優數據庫

Collections.synchronizedMap

線程安全,採用當前對象做爲鎖,顆粒較大,併發性能較差。編程

3. Int做爲Key的Map

針對該特性進行了優化,採用二分法查找,簡單數組存儲。json

SparseArraySparseBooleanArraySparseIntArrayapi

III. 數據庫相關

建多索引的原則: 哪一個字段能夠最快的減小查詢結果,就把該字段放在最前面數組

沒法使用索引的狀況

  • 操做符BETWEENLIKEOR
  • 表達式
  • CASE WHEN

不推薦

  • 不要設計出索引是其餘索引的前綴(沒有意義)
  • 更新時拒絕直接全量更新,要更新哪列就put哪列的數據
  • 若是最頻繁的是更新與插入,別建不少索引 (本來表就很小就也不必建)
  • 拒絕用大字符串建立索引
  • 避免建太多索引,查詢時可能就不會選擇最好的來執行

推薦

  • 多使用整型索引,效率遠高於字符串索引
  • 搜索時使用SQL參數("?", parameter)代替字符串拼接(底層有特殊優化與緩存)
  • 查詢須要多少就limit多少(如判斷是否含有啥,就limit 1就好了嘛)
  • 若是出現很寬的列(如blob類型),考慮放在單獨表中(在查詢或者更新其餘列數據時防止沒必要要的大數據i/o影響性能)

IV. JNI抉擇

Android JVM相關知識,可參看: ART、Dalvik

Android JNI、NDK相關知識,可參看: NDK

JNI不必定顯得更快,有些會更慢。

特色: 不用在虛擬機的框子下寫代碼

  • 能夠調用更底層的高性能的代碼庫 – Good
  • 若是是Dalvik,將省去了由JIT編譯期轉爲本地代碼的這個步驟。 – Good
  • Java調用JNI的耗時較Java調用Java確定更慢,雖然隨着JDK版本的升級,差距已經愈來愈小(JDK1.6版本是5倍Java調用Java方法的耗時) – Bad
  • 內存不在Java Heap,沒有OOM風險,有效減小gc。 – Good

一些重要的參數之類,也能夠考慮放在Native層,保證安全性。參考: Android應用程序通用自動脫殼方法研究

V. 多進程抉擇

360 17個進程: 360手機衛士 Android開發 InfoQ視頻 總結

  • 充分獨立,解耦部分
  • 大內存(如臨時展現大量圖片的Activity)、沒法解決的crash、內存泄漏等問題,考慮經過獨立進程解決
  • 獨立於UI進程,須要在後臺長期存活的服務(參看Android中線程、進程與組件的關係)
  • 非己方第三方庫(沒法保證穩定、性能等問題,而且獨立組件),可考慮獨立進程

最後,多進程存在的兩個問題: 1. 因爲進程間通信或者首次調起進程的消耗等,帶來的cpu、i/o等的資源競爭。2. 也許對於部分同事來講,會還有可讀性問題吧,畢竟多了層IPC繞了點。

VI. UI層面

相關深刻優化,可參看Android繪製佈局相關

對於卡頓相關排查推薦參看: Android性能優化案例研究(上)Android性能優化案例研究(下)

  • 減小沒必要要的不透明背景相互覆蓋,減小重繪,由於GPU不得不一遍又一遍的畫這些圖層
  • 保證UI線程一次完整的繪製(measure、layout、draw)不超過16ms(60Hz),不然就會出現掉幀,卡頓的現象
  • 在UI線程中頻繁的調度中,儘可能少的對象建立,減小gc等。
  • 分步加載(減小任務顆粒)、預加載、異步加載(區別出耗時任務,採用異步加載)

VII. 庫推薦

能夠參考Falcon Pro做者的推薦: Falcon Pro 3如何完成獨立開發演講分析

1. 代碼編寫習慣

RxJava (響應式編程,代碼更加簡潔,異步處理更快快捷、異常處理更加完全、數據管道理念)

相關了解能夠參看: RxJava

2. 圖片加載:

3. 網絡底層庫:

Okhttp: 默認gzip、緩存、安全等

4. 網絡基層:

Retrofit: 很是好用的REST Client,結合RxJava簡單API實現、類型安全,簡單快捷

5. 數據庫層:

Realm: 效率極高(Falcon Pro 3的做者Joaquim用了該庫之後,全部數據庫操做都放到了UI線程)(基於TightDB,底層C++閉源,Java層開源,簡單使用,性能遠高於SQLite等)

6. Crash上報:

Fabric: 全面的信息(新版本還支持JNI Crash獲取和上報)、穩定的數據、及時的通知、強大的反混淆(其實在混淆後有上傳mapping)

7. 內存泄漏自動化檢測

LeakCanary: 自動化泄漏檢測與分析 ( 能夠看看這個LeakCanary使用總結Leakcanary Square的一款Android/Java內存泄漏檢測工具)

8. 其餘

VIII. 內存泄漏相關

  • 沒法解決的泄漏(如系統底層引發的)移至獨立進程(如2.x機器存在webview的內存泄漏)
  • 大圖片資源/全屏圖片資源,要不放在assets下,要不放在nodpi下,要不都帶,不然縮放會帶來額外耗時與內存問題
  • 4.x在AndroidManifest中配置largeHeap=true,通常dvm heep最大值可增大50%以上。
  • Activity#onDestory之後,遍歷全部View,幹掉全部View可能的引用(一般泄漏一個Activity,連帶泄漏其上的View,而後就泄漏了大於全屏圖片的內存)。
  • 萬金油: 靜態化內部類,使用WeakReference引用外部類,防止內部類長期存在,泄漏了外部類的問題。

圖片Decode

  • 全局統一BitmapFactory#decode出口,捕獲此處decode oom,控制長寬(小於屏幕分辨率大小 )
  • 若是採用RGB_8888 oom了,嘗試RGB_565(相比內存小一半以上(wh2(bytes)))
  • 若是還考慮2.x機器的話,設置BitmapFactory#optionsInNativeAlloc參數爲true,此時decode的內存不會上報到dvm中,便不會oom。

IX. 編譯與發佈

  • 考慮採用DexGuard,或ProGuard結合相關資源混淆來提升安全與包大小,參考: DexGuard、Proguard、Multi-dex
  • 結合Gradle、Gitlab-CI 與Slack(Incoming WebHooks),快速實現,打相關git上打相關Tag,自動編相關包通知Slack。
  • 結合Gitlab-CI與Slack(Incoming WebHooks),快速實現,全部的push,Slack快速獲知。
  • 結合Gradle中Android提供的productFlavors參數,定義不一樣的variations,快速批量打渠道包

X. 其餘

  • final能用就用(高效: 編譯器在調用final方法時,會轉入內嵌機制)
  • 懶預加載,如簡單的ListView、RecyclerView等滑動列表控件,停留在當前頁面的時候,能夠考慮直接預加載下個頁面所需圖片
  • 智能預加載,經過權重等方式結合業務層面,分析出哪些更有可能被用戶瀏覽使用,而後再在某個可能的時刻進行預加載。如,進入朋友圈以前經過用戶行爲,智能預加載部分原圖。
  • 作好有損體驗的準備,在一些沒法避免的問題面前作好有損體驗(如,非UI進程crash,能夠本身解決就不要讓用戶感知,或者UI進程crash了,作好場景恢復)
  • 作好各項有效監控:crash(注意還有JNI的)、anr(按期掃描文件)、掉幀(繪製監控、activity生命週期監控等)、異常狀態監控(本地Log根據須要不一樣級別打Log並選擇性上報監控)等
  • 文件存儲推薦放在/sdcard/Android/data/[package name]/裏(在應用卸載時,會隨即刪除)(Context#getExternalFilesDir()),而非/sdcard/根目錄建文件夾(節操問題)
  • 經過gradle的shrinkResourcesminifyEnabled參數能夠簡單快速的在編包的時候自動刪除無用資源
  • 因爲resources.arsc在api8之後,aapt中默認採用UTF-8編碼,致使資源中大都是中文的resources.arsc相比採用UTF-16編碼更大,此時,能夠考慮aapt中指定使用UTF-16
  • 谷歌建議,大於10M的大型應用考慮安裝到SD卡上: App Install Location
  • 固然運維也是一方面: Optimize Your App
  • 在已知而且不須要棧數據的狀況下,就沒有必要須要使用異常,或建立Throwable生成棧快照是一項耗時的工做。
相關文章
相關標籤/搜索