Android MMKV框架引入使用
Android 敏捷開發助手
MMKV框架引入使用
- 前言
- MMKV 原理
- 功能特性
- 使用實踐
- MMKV 、 SharedPreferences、SQLite 對比
- SharedPreferences 遷移
- 總結
博客創建時間:2022.10.04
博客更新時間:2022.10.06
以Android studio build=7.0.0,SDKVersion 31來分析講解。如圖文和網上其他資料不一致,可能是別的資料版本較低而已。
前言
項目常見的輕量級存儲一般使用的是SharedPreferences,雖然 SP 兼容性極好, 但其低性能一直被詬病,線上也常出現一些SP導致的ANR。
鵝廠的開源框架MMKV能完美解決SP現有缺點并保持原有的優點。MMKV是基于 mmap 內存映射+ protobuf 序列化兩者優勢于一體的框架,其具有更高性能高,更強的穩定性。
框架源碼:https://github.com/tencent/mmkv
MMKV 原理
內存準備
通過 mmap 內存映射文件,提供一段可供隨時寫入的內存塊,App 只管往里面寫數據,由操作系統負責將內存回寫到文件,不必擔心 crash 導致數據丟失。
數據組織
數據序列化方面我們選用 protobuf 協議,pb 在性能和空間占用上都有不錯的表現。
寫入優化
考慮到主要使用場景是頻繁地進行寫入更新,我們需要有增量更新的能力。我們考慮將增量 kv 對象序列化后,append 到內存末尾。
空間增長
使用 append 實現增量更新帶來了一個新的問題,就是不斷 append 的話,文件大小會增長得不可控。我們需要在性能和空間上做個折中。
其中對于Android系統,增加了 文件鎖 來保證多進程的調用。
功能特性
多進程訪問
基于mmap技術,支持多進程數據共享
Android 平臺第一個想到的就是 ContentProvider:一個單獨進程管理數據,數據同步不易出錯,簡單好用易上手。然而它的問題也很明顯,就是一個字慢:啟動慢,訪問也慢。這個可以說是 Android 下基于Binder的CS 架構組件的通用痛點。
再考慮到 MMKV 底層使用 mmap 實現,采用去中心化的架構是很自然的選擇。我們只需要將文件 mmap 到每個訪問進程的內存空間,加上合適的進程鎖,再處理好數據的同步,就能夠實現多進程并發訪問。
匿名內存
對于敏感數據保存在文件中不適合,使用Android 特有的Ashmem 匿名共享內存技術,達到數據保密效果。
數據加密
在Android中 MMKV 使用了 AES CFB-128 算法來加密/解密。選擇 CFB 而不是常見的 CBC 算法,主要是因為 MMKV 使用 append-only 實現插入/更新操作,流式加密算法更加合適。
使用實踐
MMKV 的使用非常簡單,所有變更立馬生效,無需調用 sync、apply。
1. 依賴
implementation 'com.tencent:mmkv:1.0.10' implementation 'com.tencent:mmkv-static:1.0.23'2. 初始化
MMKV的初始化可以指定保存位置,也可以默認保存位置。
MMKV的實例可以默認生成,也可以根據不同的業務需求實例化,
// 默認MMKV 實例化 MMKV kv = MMKV.defaultMMKV(); // 根據業務區別存儲, 附帶一個自己的 ID MMKV kv2 = MMKV.mmkvWithID("MyID"); // 多進程同步支持 MMKV kv3 = MMKV.mmkvWithID("MyID", MMKV.MULTI_PROCESS_MODE);3. 遷移
MMKV支持完美無損的將SP中保存的數據遷移到MMKV中
4. 代碼MMKVUtils
MMKV使用非常簡單,已封裝成一個Utils工具,大家可以復制拿去使用
MMKV 、 SharedPreferences、SQLite 對比
單進程性能
可見,MMKV 在寫入性能上遠遠超越 SharedPreferences & SQLite,在讀取性能上也有相近或超越的表現。
多進程性能
MMKV 無論是在寫入性能還是在讀取性能,都遠遠超越 MultiProcessSharedPreferences & SQLite & SQLite, MMKV 在 Android 多進程 key-value 存儲組件上是不二之選。
優點
缺點:
MMKV使用注意
保證每一個文件存儲的數據都比較小,也就說需要把數據根據業務線存儲分散。這要就不會把虛擬內存消耗過快。
還需要在適當的時候釋放一部分內存數據,比如在App中監聽onTrimMemory方法,在Java內存吃緊的情況下進行MMKV的trim操作(不準確,我們暫時以此為信號,最好自己監聽進程中內存使用情況)。
適當的時候釋放一部分內存數據,在不需要使用的時候,最好把MMKV給close掉,甚至調用exit方法。
SharedPreferences 遷移
MMKV 提供了 importFromSharedPreferences() 函數,可以比較方便地遷移數據過來,在前面已有遷移代碼示例。
MMKV 還額外實現了一遍 SharedPreferences、SharedPreferences.Editor 這兩個 interface,在遷移的時候只需兩三行代碼即可,其他 CRUD 操作代碼都不用改。
SharedPreferences缺點:
跨進程不安全 就算使用了MODE_MULTI_PROCESS,頻繁的寫入還是會會造成數據丟失。
加載緩慢 SharedPreferences使用異步加載,由于線程沒有設置優先級,按照默認的線程優先級會造成時間片搶占機會小導致主線程長時間的等待。
全量寫入無論是調用 commit() 還是 apply(),即使我們只改動其中的一個條目,都會把整個內容全部寫到文件,寫入效率低下。
每次都需要將所有的數據加載到內存,如果存儲大量數據,會占用很多的內存。
卡頓由于提供了異步落盤的 apply 機制,在崩潰或者其他一些異常情況可能會導致數據丟失。所以當應用收到系統廣播,或者被調用 onPause 等一些時機,系統會強制把所有的 SharedPreferences 對象數據落地到磁盤。如果沒有落地完成,這時候主線程會被一直阻塞。這樣非常容易造成卡頓,甚至是 ANR,從線上數據來看 SP卡頓占比一般會超過 5%
通過 getSharedPreferences 可以獲取 SP 實例,從首次初始化到讀到數據會存在延遲,因為讀文件的操作阻塞調用的線程直到文件讀取完畢,如果在主線程調用,可能會對 UI 流暢度造成影響。(線程阻塞)
將數據寫入文件需要將數據拷貝兩次,再寫入到文件中,如果數據量過大,也會有很大的性能損耗。(二次寫入)
總結
MMKV作為一種高性能大量數據的存儲組件,對比Android傳統的存儲方式SharedPreferences和SQLite確實有不少優勢。核心是使用mmap內存映射文件,對比傳統IO,在性能上有很大優勢,并且將讀寫文件的操作變得和操作內存一樣簡單。
MMKV引入增量寫入,重整內存,通過文件大小校驗對多進程操作感知,多進程讀寫鎖等等。但它的缺點是可能造成內存的浪費,因為必須映射內存頁的整數倍,如果只存儲很少量的數據,則顯得大材小用。因此,可以作為一種數據存儲的選擇方案,在一些需要大量存儲數據場景時,替代SharedPreferences。
| 正確性 | 優 | 支持多進程安全, 使用 mmap, 由操作系統保證數據回寫的正確性 |
| 時間開銷 | 優 | 使用 mmap 實現, 減少了用戶空間數據到內核空間的拷貝 |
| 空間開銷 | 中 | 使用 protocl buffer 存儲數據, 同樣的數據會比 xml 和 json 消耗空間小 使用的是數據追加到末尾的方式, 只有到達一定閾值之后才會觸發鍵值合并, 不合并之前會導致同一個 key 存在多份 |
| 安全 | 中 | 使用 crc 校驗, 甄別文件系統和操作系統不穩定導致的異常數據 |
| 開發成本 | 優 | 使用方式較為簡單 |
| 兼容性 | 優 | 各個安卓版本都前后兼容 |
相關鏈接:
擴展鏈接:
博客書寫不易,您的點贊收藏是我前進的動力,千萬別忘記點贊、 收藏 ^ _ ^ !
總結
以上是生活随笔為你收集整理的Android MMKV框架引入使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL中的alter table操作
- 下一篇: 单例模式(C++)