Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發優化寶典

Android開發優化寶典

編輯:關於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. 輸入流

使用具有緩存策略的輸入流

建議替換為

   

InputStream

BufferedInputStream

Reader

BufferedReader

 

II. 數據結構

 

如果已知大概需要多大,就直接給初始大小,減少擴容時額外開銷。

1. List

ArrayList

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

LinkedList

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

 

2. Hash

HashSet

裡面就一個HashMap,用key對外存儲,目的就是不允許重復元素。

ConcurrentHashMap

線程安全,采用細分鎖,鎖顆粒更小,並發性能更優

Collections.synchronizedMap

線程安全,采用當前對象作為鎖,顆粒較大,並發性能較差。

 

3. Int作為Key的Map

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

SparseArray、SparseBooleanArray、SparseIntArray。

 

III. 數據庫相關

建多索引的原則: 哪個字段可以最快的減少查詢結果,就把該字段放在最前面

無法使用索引的情況

  • 操作符BETWEEN、LIKE、OR

  • 表達式

  • 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. 圖片加載:

  • 小型快捷:Picasso(接口干淨、支持okhttp、功能強大、穩定、高效, 可以延讀:PhotoGallery、Volley、Picasso 比較)

  • 大項目考慮:Fresco(2.5M,pipeline解決資源競爭、Native Heep解決OOM,的同時減少GC)

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. 其他

  • 代碼質量:phabricator 的arc diff(盡量小顆粒度的arc diff 與update review),其實也可以看看Google是如何做的:筆記-谷歌是如何做代碼審查的,還有一點的TODO要寫好deadline與master

  • 編包管理:Gitlab CI(結合Gitlab,功能夠用,方便)

 

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#options的InNativeAlloc參數為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的shrinkResources與minifyEnabled參數可以簡單快速的在編包的時候自動刪除無用資源

  • 由於resources.arsc在api8以後,aapt中默認采用UTF-8編碼,導致資源中大都是中文的resources.arsc相比采用UTF-16編碼更大,此時,可以考慮aapt中指定使用UTF-16

  • 谷歌建議,大於10M的大型應用考慮安裝到SD卡上:App Install Location

  • 當然運維也是一方面:Optimize Your App

  • 在已知並且不需要棧數據的情況下,就沒有必要需要使用異常,或創建Throwable生成棧快照是一項耗時的工作。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved