MMVK替換SP實現(xiàn)本地數(shù)據(jù)持有化

引言

最近將項目中的sharedpreference替換了微信開源的mmkv框架损俭,記錄下兩者之前的性能對比和mmvk的簡單封裝使用

MMKV原理

  • 內(nèi)存準備
    通過 mmap 內(nèi)存映射文件骑篙,提供一段可供隨時寫入的內(nèi)存塊,App 只管往里面寫數(shù)據(jù)威鹿,由操作系統(tǒng)負責將內(nèi)存回寫到文件吱韭,不必擔心 crash 導致數(shù)據(jù)丟失棱烂。
  • 數(shù)據(jù)組織
    數(shù)據(jù)序列化方面我們選用 protobuf 協(xié)議,pb 在性能和空間占用上都有不錯的表現(xiàn)喇伯。
  • 寫入優(yōu)化
    考慮到主要使用場景是頻繁地進行寫入更新喊儡,我們需要有增量更新的能力。我們考慮將增量 kv 對象序列化后稻据,append 到內(nèi)存末尾艾猜。
  • 空間增長
    使用 append 實現(xiàn)增量更新帶來了一個新的問題,就是不斷 append 的話,文件大小會增長得不可控匆赃。我們需要在性能和空間上做個折中淤毛。

替換原因

1,數(shù)據(jù)加密算柳。 在 Android 環(huán)境里低淡,數(shù)據(jù)加密是非常必須的,SP實際上是把鍵值對放到本地文件中進行存儲瞬项。如果要保證數(shù)據(jù)安全需要自己加密蔗蹋,MMKV 使用了 AES CFB-128 算法來加密/解密。

2滥壕,多進程共享纸颜。系統(tǒng)自帶的 SharedPreferences 對多進程的支持不好。現(xiàn)有基于 ContentProvider 封裝的實現(xiàn)绎橘,雖然多進程是支持了胁孙,但是性能低下,經(jīng)常導致 ANR称鳞′探希考慮到 mmap 共享內(nèi)存本質(zhì)上是多進程共享的,MMKV 在這個基礎上冈止,深入挖掘了Android 系統(tǒng)的能力狂票,提供了可能是業(yè)界最高效的多進程數(shù)據(jù)共享組件。

3熙暴,匿名內(nèi)存闺属。 在多進程共享的基礎上,考慮到某些敏感數(shù)據(jù)(例如密碼)需要進程間共享周霉,但是不方便落地存儲到文件上掂器,直接用 mmap 不合適。而Android 系統(tǒng)提供了 Ashmem 匿名共享內(nèi)存的能力俱箱,它在 進程退出后就會消失国瓮,不會落地到文件上,非常適合這個場景狞谱。MMKV 基于此也提供了 Ashmem(匿名共享內(nèi)存) MMKV 的功能乃摹。

4,效率更高跟衅。MMKV 使用protobuf進行序列化和反序列化孵睬,比起SP的xml存放方式,更加高效与斤。

5肪康,支持從 SP遷移荚恶,如果你之前項目里面都是使用SP,現(xiàn)在想改為使用MMKV磷支,只需幾行代碼即可將之前的SP實現(xiàn)遷移到MMKV谒撼。

支持的數(shù)據(jù)類型

1,支持以下 Java 語言基礎類型:

 boolean雾狈、int廓潜、long、float善榛、double辩蛋、byte[]

2,支持以下 Java 類和容器:

String移盆、Set< String >

任何實現(xiàn)了Parcelable的類型

使用

1.添加依賴庫

dependencies {
 implementation 'com.tencent:mmkv:1.0.23'
}

2.在application中初始化

MMKV.initialize(this); 

3.獲取mmkv實例

正常單一業(yè)務儲存
MMKV kv = MMKV.defaultMMKV();

如果不同業(yè)務需要區(qū)別存儲悼院,也可以單獨創(chuàng)建自己的實例:
MMKV mmkv = MMKV.mmkvWithID("MyID");

默認支持單進程的,如果業(yè)務需要多進程訪問咒循,則需要加上標志位 MMKV.MULTI_PROCESS_MODE:
MMKV mmkv = MMKV.mmkvWithID("InterProcessKV", MMKV.MULTI_PROCESS_MODE);

自定義跟目錄据途,MMKV 默認把文件存放在$(FilesDir)/mmkv/目錄。你可以在 App 啟動時自定義根目錄:
String dir = getFilesDir().getAbsolutePath() + "/mmkv_2";
String rootDir = MMKV.initialize(dir);
class SpUtils private constructor() {
    private var mv: MMKV = MMKV.defaultMMKV()

    /**
     * 保存數(shù)據(jù)的方法叙甸,我們需要拿到保存數(shù)據(jù)的具體類型颖医,然后根據(jù)類型調(diào)用不同的保存方法
     *
     * @param key
     * @param object
     */
    fun encode(key: String?, `object`: Any) {
        if (`object` is String) {
            mv.encode(key, `object`)
        } else if (`object` is Int) {
            mv.encode(key, `object`)
        } else if (`object` is Boolean) {
            mv.encode(key, `object`)
        } else if (`object` is Float) {
            mv.encode(key, `object`)
        } else if (`object` is Long) {
            mv.encode(key, `object`)
        } else if (`object` is Double) {
            mv.encode(key, `object`)
        } else if (`object` is ByteArray) {
            mv.encode(key, `object`)
        } else {
            mv.encode(key, `object`.toString())
        }
    }

    fun encodeSet(key: String?, sets: Set<String?>?) {
        mv.encode(key, sets)
    }

    fun encodeParcelable(key: String?, obj: Parcelable?) {
        mv.encode(key, obj)
    }

    /**
     * 得到保存數(shù)據(jù)的方法,我們根據(jù)默認值得到保存的數(shù)據(jù)的具體類型裆蒸,然后調(diào)用相對于的方法獲取值
     */
    fun decodeInt(key: String?): Int {
        return mv.decodeInt(key, 0)
    }

    fun decodeDouble(key: String?): Double {
        return mv.decodeDouble(key, 0.00)
    }

    fun decodeLong(key: String?): Long {
        return mv.decodeLong(key, 0L)
    }

    fun decodeBoolean(key: String?): Boolean {
        return mv.decodeBool(key, false)
    }

    fun decodeFloat(key: String?): Float {
        return mv.decodeFloat(key, 0f)
    }

    fun decodeBytes(key: String?): ByteArray {
        return mv.decodeBytes(key)
    }

    fun decodeString(key: String?): String {
        return mv.decodeString(key, "")
    }

    fun decodeStringSet(key: String?): Set<String> {
        return mv.decodeStringSet(key, emptySet())
    }

    fun <T : Parcelable?> decodeParcelable(key: String?, tClass: Class<T>?): T {
        return mv.decodeParcelable(key, tClass)
    }

    /**
     * 移除某個key對
     *
     * @param key
     */
    fun removeKey(key: String?) {
        mv.removeValueForKey(key)
    }

    /**
     * 清除所有key
     */
    fun clearAll() {
        mv.clearAll()
    }
    /**
     * 從sp中遷移到mmvk
     */
    fun testImportSharedPreferences(context: Context){
        val old_man = context.getSharedPreferences("myData", Context.MODE_PRIVATE)
        // 遷移舊數(shù)據(jù)
        mv.importFromSharedPreferences(old_man);
        // 清空舊數(shù)據(jù)
        old_man.edit().clear().commit();
    }



    companion object {
        private var mInstance: SpUtils? = null

        /**
         * 初始化MMKV,只需要初始化一次熔萧,建議在Application中初始化
         *
         */
        val instance: SpUtils?
            get() {
                if (mInstance == null) {
                    synchronized(SpUtils::class.java) {
                        if (mInstance == null) {
                            mInstance = SpUtils()
                        }
                    }
                }
                return mInstance
            }
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市僚祷,隨后出現(xiàn)的幾起案子佛致,更是在濱河造成了極大的恐慌,老刑警劉巖辙谜,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晌杰,死亡現(xiàn)場離奇詭異,居然都是意外死亡筷弦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門抑诸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烂琴,“玉大人,你說我怎么就攤上這事蜕乡〖楸粒” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵层玲,是天一觀的道長号醉。 經(jīng)常有香客問我反症,道長,這世上最難降的妖魔是什么畔派? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任铅碍,我火速辦了婚禮,結(jié)果婚禮上线椰,老公的妹妹穿的比我還像新娘胞谈。我一直安慰自己,他們只是感情好憨愉,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布烦绳。 她就那樣靜靜地躺著,像睡著了一般配紫。 火紅的嫁衣襯著肌膚如雪径密。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天躺孝,我揣著相機與錄音享扔,去河邊找鬼。 笑死括细,一個胖子當著我的面吹牛伪很,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奋单,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锉试,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了览濒?” 一聲冷哼從身側(cè)響起呆盖,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贷笛,沒想到半個月后应又,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡乏苦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年株扛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汇荐。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡洞就,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掀淘,到底是詐尸還是另有隱情旬蟋,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布革娄,位于F島的核電站倾贰,受9級特大地震影響冕碟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜匆浙,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一安寺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吞彤,春花似錦我衬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至埋嵌,卻和暖如春破加,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雹嗦。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工范舀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人了罪。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓锭环,卻偏偏與公主長得像,于是被迫代替她去往敵國和親泊藕。 傳聞我的和親對象是個殘疾皇子辅辩,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容