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