日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

android mmkv使用_Android:MMKV 组件入门

發(fā)布時間:2023/12/20 Android 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android mmkv使用_Android:MMKV 组件入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、前言:

MMKV 是騰訊開源的一款基于 mmap 內(nèi)存映射的 key-value 組件,底層序列化/反序列化使用 protobuf 實(shí)現(xiàn),性能高,穩(wěn)定性強(qiáng),從 2015 年中至今在微信上使用,其性能和穩(wěn)定性經(jīng)過了時間的驗(yàn)證。GitHub地址:https://github.com/Tencent/MMKV

1、為什么要替代SharedPreferences?

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

2,多進(jìn)程共享。系統(tǒng)自帶的 SharedPreferences 對多進(jìn)程的支持不好。現(xiàn)有基于 ContentProvider 封裝的實(shí)現(xiàn),雖然多進(jìn)程是支持了,但是性能低下,經(jīng)常導(dǎo)致 ANR。考慮到 mmap 共享內(nèi)存本質(zhì)上是多進(jìn)程共享的,MMKV 在這個基礎(chǔ)上,深入挖掘了 Android 系統(tǒng)的能力,提供了可能是業(yè)界最高效的多進(jìn)程數(shù)據(jù)共享組件。

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

4,效率更高。MMKV 使用protobuf進(jìn)行序列化和反序列化,比起SP的xml存放方式,更加高效。

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

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

1,支持以下 Java 語言基礎(chǔ)類型:

boolean、int、long、float、double、byte[]

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

String、Set< String >

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

二、使用:

1、添加依賴

dependencies {

implementation 'com.tencent:mmkv-static:1.2.7'

}

2、初始化

在自定義的Application中:

MMKV.initialize(this);

3、數(shù)據(jù)操作(工具類封裝)

MMKV 提供一個全局的實(shí)例,可以直接使用:

MMKV kv = MMKV.defaultMMKV();

kv.encode("bool", true);

kv.encode("int", Integer.MIN_VALUE);

kv.encode("float", -3.14f);

kv.encode("string", "Hello from mmkv");

byte[] bytes = {'m', 'm', 'k', 'v'};

kv.encode("bytes",bytes);

//打印結(jié)果:

Timber.d("bool值: "+ kv.decodeBool("bool"));

Timber.d("int值: "+ kv.decodeInt("int"));

Timber.d("float值: "+ kv.decodeFloat("float"));

Timber.d("string值: "+ kv.decodeString("string"));

Timber.d("bytes值: "+ new String(kv.decodeBytes("bytes")));

Timber.d("1是否包含: "+ kv.containsKey("stringName"));

Timber.d("2是否包含: "+ kv.containsKey("stringffName"));

結(jié)果:

com.sumansoul.myviewdemo D/MainActivity: bool值: true

com.sumansoul.myviewdemo D/MainActivity: int值: -2147483648

com.sumansoul.myviewdemo D/MainActivity: float值: -3.14

com.sumansoul.myviewdemo D/MainActivity: string值: Hello from mmkv

com.sumansoul.myviewdemo D/MainActivity: bytes值: mmkv

com.sumansoul.myviewdemo D/MainActivity: 1是否包含: true

com.sumansoul.myviewdemo D/MainActivity: 2是否包含: false

4、刪除 & 查詢:

MMKV kv = MMKV.defaultMMKV();

kv.removeValueForKey("bool");

System.out.println("bool: " + kv.decodeBool("bool"));

kv.removeValuesForKeys(new String[]{"int", "long"});

System.out.println("allKeys: " + Arrays.toString(kv.allKeys()));

kv.clearAll();

boolean hasBool = kv.containsKey("bool");

5、如果不同業(yè)務(wù)需要區(qū)別存儲,也可以單獨(dú)創(chuàng)建自己的實(shí)例:

MMKV mmkv = MMKV.mmkvWithID("MyID");

mmkv.encode("bool", true);

6、默認(rèn)是支持單進(jìn)程的,如果業(yè)務(wù)需要多進(jìn)程訪問,那么在初始化的時候加上標(biāo)志位 MMKV.MULTI_PROCESS_MODE:

MMKV mmkv = MMKV.mmkvWithID("InterProcessKV", MMKV.MULTI_PROCESS_MODE);

mmkv.encode("bool", true);

三、自定義根目錄

MMKV 默認(rèn)把文件存放在$(FilesDir)/mmkv/目錄。你可以在 App 啟動時自定義根目錄:

String dir = getFilesDir().getAbsolutePath() + "/mmkv_2";

String rootDir = MMKV.initialize(dir);

Log.i("MMKV", "mmkv root: " + rootDir);

MMKV 甚至支持自定義某個文件的目錄:

String relativePath = getFilesDir().getAbsolutePath() + "/mmkv_3";

MMKV kv = MMKV.mmkvWithID("testCustomDir", relativePath);

四、工具類封裝如下:

1、工具類:

public class SpUtils {

private static SpUtils mInstance;

private static MMKV mv;

private SpUtils() {

mv = MMKV.defaultMMKV();

}

/**

* 初始化MMKV,只需要初始化一次,建議在Application中初始化

*

*/

public static SpUtils getInstance() {

if (mInstance == null) {

synchronized (SpUtils.class) {

if (mInstance == null) {

mInstance = new SpUtils();

}

}

}

return mInstance;

}

/**

* 保存數(shù)據(jù)的方法,我們需要拿到保存數(shù)據(jù)的具體類型,然后根據(jù)類型調(diào)用不同的保存方法

*

* @param key

* @param object

*/

public static void encode(String key, Object object) {

if (object instanceof String) {

mv.encode(key, (String) object);

} else if (object instanceof Integer) {

mv.encode(key, (Integer) object);

} else if (object instanceof Boolean) {

mv.encode(key, (Boolean) object);

} else if (object instanceof Float) {

mv.encode(key, (Float) object);

} else if (object instanceof Long) {

mv.encode(key, (Long) object);

} else if (object instanceof Double) {

mv.encode(key, (Double) object);

} else if (object instanceof byte[] ) {

mv.encode(key, (byte[]) object);

} else {

mv.encode(key, object.toString());

}

}

public static void encodeSet(String key, Set sets) {

mv.encode(key, sets);

}

public static void encodeParcelable(String key, Parcelable obj) {

mv.encode(key, obj);

}

/**

* 得到保存數(shù)據(jù)的方法,我們根據(jù)默認(rèn)值得到保存的數(shù)據(jù)的具體類型,然后調(diào)用相對于的方法獲取值

*/

public static Integer decodeInt(String key) {

return mv.decodeInt(key, 0);

}

public static Double decodeDouble(String key) {

return mv.decodeDouble(key, 0.00);

}

public static Long decodeLong(String key) {

return mv.decodeLong(key, 0L);

}

public static Boolean decodeBoolean(String key) {

return mv.decodeBool(key, false);

}

public static Float decodeFloat(String key) {

return mv.decodeFloat(key, 0F);

}

public static byte[] decodeBytes(String key) {

return mv.decodeBytes(key);

}

public static String decodeString(String key) {

return mv.decodeString(key,"");

}

public static Set decodeStringSet(String key) {

return mv.decodeStringSet(key, Collections.emptySet());

}

public static Parcelable decodeParcelable(String key) {

return mv.decodeParcelable(key, null);

}

/**

* 移除某個key對

*

* @param key

*/

public static void removeKey(String key) {

mv.removeValueForKey(key);

}

/**

* 清除所有key

*/

public static void clearAll() {

mv.clearAll();

}

/**

* 是否包含某個key

*/

public static boolean containsKey(String key) {

return mv.containsKey(key);

}

}

2、在application中初始化:

//數(shù)據(jù)存儲初始化

MMKV.initialize(this);

SpUtils.getInstance();

3、Activity中使用:

SpUtils.encode("stringName","中國歡迎你");

SpUtils.encode("boolName",true);

SpUtils.encode("intName",1204);

//打印日志

Timber.d("bool值: "+ SpUtils.decodeBoolean("boolName"));

Timber.d("int值: "+ SpUtils.decodeInt("intName"));

Timber.d("string值: "+ SpUtils.decodeString("stringName"));

結(jié)果:

2021-02-22 16:45:51.444 13379-13379/com.sumansoul.myviewdemo D/MainActivity: bool值: true

2021-02-22 16:45:51.444 13379-13379/com.sumansoul.myviewdemo D/MainActivity: int值: 1204

2021-02-22 16:45:51.445 13379-13379/com.sumansoul.myviewdemo D/MainActivity: string值: 中國歡迎你

五、MMKV組件實(shí)現(xiàn)原理以及和SharedPreferences的比較

1、MMKV:

原理:MMKV是基于mmap內(nèi)存映射關(guān)系的key-value組件,底層序列化/反序列化使用protobuf實(shí)現(xiàn)。性能高,穩(wěn)定性強(qiáng)。從2015年就在微信上使用,已經(jīng)移植到了Android/MacOS/Windows平臺

MMAP的優(yōu)勢:

MMAP對文件的讀寫操作只需要 從磁盤到用戶主存的一次數(shù)據(jù)拷貝,減少了數(shù)據(jù)拷貝次數(shù),提高了文件讀寫效率;

MMAP使用邏輯內(nèi)存對此盤文件進(jìn)行映射,操作內(nèi)存就相當(dāng)于操作文件,不需要開啟線程,操作MMAP的速度和操作內(nèi)存一樣快;

MMAP提供一段可以隨時寫入的內(nèi)存塊,APP只管往里面寫數(shù)據(jù),在內(nèi)存不足,進(jìn)程退出的情況下由操作系統(tǒng)負(fù)責(zé)將數(shù)據(jù)寫回到文件,不必?fù)?dān)心Crash導(dǎo)致數(shù)據(jù)丟失;

2、SharedPreferences:

原理:SharedPreferences是Android提供的一種使用XML文件保存內(nèi)容的機(jī)制,內(nèi)部通過XML寫入文件。

特點(diǎn):

讀寫方式:直接I/O(耗時,容易出現(xiàn)anr)

數(shù)據(jù)格式:xml

寫入方式:全量更新

總結(jié)

以上是生活随笔為你收集整理的android mmkv使用_Android:MMKV 组件入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。