概述
本文主要簡述SharedPreferences存儲的使用及優(yōu)劣勢剩辟,以及MMKV內(nèi)容。
一珍德、SharedPreferences
SharedPreferences(以下使用SP簡稱)是在Android中的一種輕量級的存儲方式尉剩,支持開發(fā)者將基本類型數(shù)據(jù)以鍵值對的形式進行存儲面粮。SP具有在應(yīng)用內(nèi)數(shù)據(jù)可以共享,使用簡單方便的優(yōu)點。
SP會將數(shù)據(jù)以文件的形式進行存儲竹宋,具體路徑:
/data/data/<packagename>/shared_prefs/
下面對于SP的使用進行簡單說明劳澄。
使用
使用SP首先需要需要獲取SP對象,可以通過Context.getSharedPreferences(key, Context.MODE_PRIVATE)
獲取到SP對象蜈七。
注意:Mode目前只有Context.MODE_PRIVATE秒拔,表示此文件是私有數(shù)據(jù),只能夠被應(yīng)用本身訪問飒硅,寫入覆蓋砂缩。其余的在新版API中均已廢棄。
1. 存儲數(shù)據(jù)
示例代碼如下:
var sp = this.getSharedPreferences("test",Context.MODE_PRIVATE)
var edit = sp.edit()
edit.putBoolean("flag",true)
edit.putInt("temp",1) //統(tǒng)一put完數(shù)據(jù)再提交三娩,否則可能會空異常
edit.apply() //edit.commit()
commit()
和apply()
都可以提交SP存儲庵芭,但是兩者有所區(qū)別:
-
apply()
立刻更改內(nèi)存中的SP值,但是會異步的將更新寫入磁盤雀监,無返回值 -
commit()
則是會同步的寫入的磁盤双吆,需要注意其調(diào)用的線程(不要放在主線程),有返回值会前,返回是否成功的寫入存儲好乐。
2. 取數(shù)據(jù)
示例代碼如下:
var sp = this.getSharedPreferences("test",Context.MODE_PRIVATE)
var result = sp.getBoolean("flag",false) //第二個參數(shù)是沒有獲取到數(shù)據(jù)的默認值
獲取到SP對象之后直接get即可,使用方便瓦宜。
二蔚万、MMKV
MMKV是騰訊開源的一款基于mmap內(nèi)存映射的鍵值對組件,底層序列化次用了prorobuf實現(xiàn)歉提,性能高且穩(wěn)定性良好笛坦,能夠很好的取代SP存儲。
1. SP的缺點和MMKV的優(yōu)勢
SP雖然簡單易用苔巨,但是在開發(fā)過程中依然存在不少缺點版扩,具體如下:
- 多進程共享。系統(tǒng)自帶的SP存儲對于多進程幾乎不支持侄泽,并且官方文檔上明確指出SP不能使用在多進程上礁芦,如果要實現(xiàn)SP存儲支持多進程,必須由我們手動去封裝ContentProvider實現(xiàn)悼尾,實現(xiàn)較復(fù)雜并且性能低下柿扣。
- 數(shù)據(jù)加密。SP存儲實際上是將鍵值對數(shù)據(jù)放到本機文件中進行存儲闺魏,如果需要數(shù)據(jù)安全需要自己加密未状。
- 效率一般。SP是以xml進行存儲的析桥,大量數(shù)據(jù)不能使用該方式存儲司草。
- 只支持基本數(shù)據(jù)類型艰垂,支持存儲的數(shù)據(jù)類型有booleans, floats, ints, longs, and strings。
針對如上的幾個缺點埋虹,MMKV都進行了改進:
- MMKV支持多進行共享猜憎。MMKV是基于mmap內(nèi)存映射的方式,而mmap共享內(nèi)存本質(zhì)上是多進程共享的搔课,因此MMKV是支持多進行共享并且效率較高胰柑。
- 數(shù)據(jù)加密。MMKV采用了AES CFB-128算法進行加密解密爬泥。
- MMKV采用了跨平臺的protobuf進行序列化和反序列化柬讨,比起SP的xml存放方式更加高效。
- 支持從SP遷移急灭。MMKV對于SP遷移做了很多支持姐浮,項目內(nèi)如果想由SP遷移到MMKV十分方便。
- 支持更多的數(shù)據(jù)類型葬馋,不但支持boolean卖鲤、int、long畴嘶、float蛋逾、double、byte[]窗悯,還支持String区匣,Set<String>以及實現(xiàn)了Parcelable的類型。
綜上所述蒋院,MMKV有著速度快亏钩,方便易用的優(yōu)勢,下面對其使用進行簡單說明欺旧。
2. 使用
1. 包引入及初始化
首先需要引入MMKV包姑丑,在buil.gradle
中添加如下內(nèi)容:
implementation 'com.tencent:mmkv:1.2.7'
然后需要在自定義Application中添加初始化內(nèi)容:
MMKV.initialize(this)
2. MMKV對象獲取
MMKV提供了一個全局的實例,可以直接使用:
var mmkv = MMKV.defaultMMKV()
也可以自定義MMKV對象辞友,設(shè)置自定ID
var mmkv2 = MMKV.mmkvWithID("id")
MMKV默認是支持單進程的栅哀,如果業(yè)務(wù)需要多進程訪問,需要在初始化的時候添加多進程模式參數(shù):
var mmkv3 = MMKV.mmkvWithID("myId",MMKV.MULTI_PROCESS_MODE)
3. 存取方法
使用MMKV的存取比較簡單称龙,方法如下:
//存儲方法
mmkv?.encode(key,data)
//獲取方法
mmkv?.decodeString(key,"defaultValues")
獲取方法需要根據(jù)類型進行自己選擇留拾。
4. 自定義文件目錄
MMKV 默認把文件存放在$(FilesDir)/mmkv/目錄。你可以在 MMKV初始化時自定義根目錄:
val dir = filesDir.absolutePath + "/mmkv_2"
val rootDir = MMKV.initialize(dir)
5. SP遷移
MMKV可以調(diào)用importFromSharedPreferences
方法進行SP的數(shù)據(jù)遷移鲫尊,示例代碼如下:
MMKV實現(xiàn)了SharedPreferences
痴柔,Editor
兩個接口,所以在遷移之后SP的操作代碼可以不用更改疫向。
val mmkv = MMKV.mmkvWithID("myData")
val olderData = DemoApplication.mContext?.getSharedPreferences("myData", MODE_PRIVATE)
mmkv?.importFromSharedPreferences(olderData)
olderData?.edit()?.clear()?.apply()
三竞帽、 MMKV優(yōu)勢及原理
為了能夠理清MMKV的優(yōu)勢扛施,我們首先需要先了解SP的工作原理。
1. SP的工作原理
SP是采用的IO寫入數(shù)據(jù)的屹篓,Linux中存在有虛擬內(nèi)存概念:用戶空間和內(nèi)核空間。
用戶空間是用戶程序代碼運行的地方匙奴,內(nèi)核空間是內(nèi)核代碼運行的地方堆巧。為了減小程序崩潰影響,兩個控件時隔離的泼菌,也就是說即使運行在用戶控件的用戶程序崩潰谍肤,內(nèi)核也不會受到影響。
SP采用了IO讀寫的操作哗伯,以read為例子說明荒揣,具體步驟如下:
- 從磁盤讀取數(shù)據(jù),將文件內(nèi)從硬盤拷貝到內(nèi)核空間的緩存區(qū)焊刹。
- 然后再將數(shù)據(jù)拷貝到用戶控件供程序使用系任。
從上面兩步中我們可以拷貝過程進行了兩次,如果數(shù)據(jù)量比較大虐块,性能損耗也會隨之提升俩滥。
2. MMKV原理
MMKV的實現(xiàn)原理是mmap(內(nèi)存映射),它是共享內(nèi)存的一種(另一種是System V,可用于跨進程)贺奠,原理如圖所示:
在Linux中霜旧,每個進程都有著屬于自己的進程控制塊(PCB)和地址空間,通過頁面將進程的虛擬地址和物理地址進行映射儡率。mmap方法會把文件內(nèi)容映射到一段虛擬內(nèi)存上挂据,通過對此段內(nèi)存的讀取和修改,實現(xiàn)對文件的讀取和修改儿普。
在mmap之后崎逃,并不會將文件內(nèi)容直接加載到物理頁上,只是在虛擬內(nèi)存中分配了地址空間箕肃,當首次訪問這段地址時婚脱,才會去通過查找頁表,但是此時虛擬內(nèi)存對應(yīng)的頁上沒有在物理內(nèi)存中緩存勺像,則會造成“缺頁”障贸,將文件對應(yīng)內(nèi)容加載到物理內(nèi)存上。
相對于普通的IO讀寫吟宦,mmap具有如下優(yōu)勢:
- 對文件的讀取操作跨過了頁緩存篮洁,減少了數(shù)據(jù)的拷貝次數(shù),操作內(nèi)存就相當于操作文件殃姓,提高了文件讀取效率袁波。
- 實現(xiàn)了用戶空間和內(nèi)核空間的高效交互方式瓦阐,修改能夠直接反映在映射的區(qū)域內(nèi),從而被對方空間及時獲取篷牌。
當然還有如下的缺點:
- 即使文件很小睡蟋,甚至于只有幾個字節(jié),但是內(nèi)存的最小粒度是頁枷颊,因此會占用整頁的大小戳杀,在連續(xù)mmap小文件,會造成內(nèi)容空間的浪費夭苗。
- 對于變長文件不適合信卡,文件無法完成拓展。
Protobuf協(xié)議
SP存儲采用的是xml文件的形式去存儲鍵值對题造,而MMKV是通過protobuf協(xié)議來實現(xiàn)的傍菇,存儲方式為增量更新,也就是不需要每次修改數(shù)據(jù)都要重新將所有的數(shù)據(jù)寫入文件界赔,速度上和大小上都優(yōu)于xml丢习。
protobuf是Google開源的一個序列化框架,類似于xml仔蝌,json泛领,最大的特點是基于二進制,比一般的xml表示同樣的內(nèi)容要短小的多敛惊。想要了解學(xué)習(xí)的朋友可以在Protobuf官網(wǎng)學(xué)習(xí)一下渊鞋,在此不再做更多的說明。
總結(jié)
相對于SP而言瞧挤,MMKV無論是在速度上還是在文件大小上都更具有優(yōu)勢锡宋,是一個很方便易用的框架。