本系列博文 基於是前微信高階工程師張紹文專欄 《Android開發高手課》的讀書筆記。
文章所寫內容是本人讀完的感悟,需要原文的朋友請自行購買。
儲存優化篇
Android分割槽
分割槽簡單來說就是將裝置中的儲存劃分為一些互不重疊的部分,每個部分都可以單獨格式化,用作不同的目的。
- /system: 作業系統預留,用來儲存系統檔案和框架的,系統升級和恢復時會擦除這一整塊分割槽
- /data: 用來儲存使用者資料的地方,手機上恢復出廠設定的那個操作就只會擦除這部分資料
- /cache: 系統升級或者恢復時的備用分割槽
- /vendor: 用來存放手機廠商對Android系統的修改
- /storge: 內建或者外接的sdcard
資料儲存需要考慮哪些要素
資料儲存就是把特定的資料結構轉化成可以被記錄和還原的格式,這個資料格式可以是二進位制的,也可以是 XML、JSON、Protocol Buffer 這些格式。
在選擇資料儲存的時候需要考慮的要素
資料儲存的選項
- SharedPreferences
- ContentProvider
- 檔案
- 資料庫
SharedPreferences
使用場景
用於儲存一些非常簡單,輕量的資料。
優點
- 系統支援,使用簡單
- 相容性強
缺點
- 跨程式不安全
- 載入緩慢。SharedPreferences 檔案的載入使用了非同步執行緒,而且載入執行緒並沒有設定執行緒優先順序,如果這個時候主執行緒讀取資料就需要等待檔案載入執行緒的結束
- 全量寫入。無論是呼叫 commit() 還是 apply(),即使我們只改動其中的一個條目,都會把整個內容全部寫到檔案。而且即使我們多次寫入同一個檔案,SP 也沒有將多次修改合併為一次,這也是效能差的重要原因之一。
基於以上原因,各大公司都會有對應的一個替代的儲存方案,比如微信的MMKV
ContentProvider
使用場景
跨程式,跨應用程式之間的大資料量互動,總體來說ContentProvider的整體框架還是不錯的,目前市面上好像也沒有什麼自研的架構替代。
需要注意的點
ContentProvider 的生命週期預設在 Application onCreate() 之前,而且都是在主執行緒建立的。我們自定義的 ContentProvider 類的建構函式、靜態程式碼塊、onCreate 函式都儘量不要做耗時的操作,會拖慢啟動速度。
物件的序列化
Serializable
java原生的序列化機制,其本身是通過 ObjectInputStream 和 ObjectOutputStream 來實現的,由於在序列化過程中使用了大量的反射和臨時變數使得效能下降,檔案體積變大。
需要注意的點
- 不被序列化的欄位。類的 static 變數以及被宣告為 transient 的欄位,預設的序列化機制都會忽略該欄位,不會進行序列化儲存。當然我們也可以使用進階的 writeReplace 和 readResolve 方法做自定義的序列化儲存。
- serialVersionUID。在類實現了 Serializable 介面後,我們需要新增一個 Serial Version ID,它相當於類的版本號。這個 ID 我們可以顯式宣告也可以讓編譯器自己計算。通常我建議顯式宣告會更加穩妥,因為隱式宣告假如類發生了一點點變化,進行反序列化都會由於 serialVersionUID 改變而導致 InvalidClassException 異常。
- 構造方法。Serializable 的反序列預設是不會執行建構函式的,它是根據資料流中對 Object 的描述資訊建立物件的。如果一些邏輯依賴建構函式,就可能會出現問題,例如一個靜態變數只在建構函式中賦值,當然我們也可以通過進階方法做自定義的反序列化修改。
Parcelable
主要解決Serializable效能低下的問題。
使用Parcelable比Serializable需要多新增一些自定義程式碼,正是因為這些程式碼,使得Parcelable在序列化的時候不需要採用大量反射這種耗時的行為,從而提高效能。
需要注意的點
使用Parcelable進行永久儲存的話,會存在一些問題。
- 系統版本的相容性。由於 Parcelable 設計本意是在記憶體中使用的,我們無法保證所有 Android 版本的Parcel.cpp實現都完全一致。如果不同系統版本實現有所差異,或者有廠商修改了實現,可能會存在問題。
- 資料前後相容性。Parcelable 並沒有版本管理的設計,如果我們類的版本出現升級,寫入的順序及欄位型別的相容都需要格外注意,這也帶來了很大的維護成本。
一般來說,如果需要持久化儲存的話,一般還是不得不選擇效能更差的 Serializable 方案。
Serial
Twitter開源的Serial保留了Serializable和Parcelable的大部分優點
資料的序列化
Serial 效能看起來還不錯,但是物件的序列化要記錄的資訊還是比較多,在操作比較頻繁的時候,對應用的影響還是不少的,這個時候我們可以選擇使用資料的序列化。
JSON
優點
- 相比物件序列化方案,速度更快,體積更小。
- 相比二進位制的序列化方案,結果可讀,易於排查問題。
- 使用方便,支援跨平臺、跨語言,支援巢狀引用。
市面上可用的框架有Android自帶的JSON庫,Google的Gson,阿里的FastJson,美團的MSON
總的來說Gson的相容性最好,資料量極大時,FastJson的效能最佳。
Protocol Buffers
二進位制序列化方案,資料量龐大的時候效能優於JSON,
資料庫優化
推薦使用自帶的SQLite,Realm或者Google的LevelDB。
這部分內容在張老師文中提到的多是執行緒併發,索引優化,page和快取處理等。比較深,這裡就不提了。