android mmkv使用_Android:MMKV 组件入门
一、前言:
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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是BSP工程师?
- 下一篇: android sina oauth2.