MMKV 工具类
最近使用了MMKV ,效果真的很棒,特意弄了两个MMKV 存储工具类,送给伸手党。
依赖: implementation ‘com.tencent:mmkv-shared:1.2.13’
一定要在Application中初始化MMKV
MMKV.initialize(this)
Java代码
/**
* @author :Create by Xia燚
* 时间:2022/7/5
* 邮箱:XiahaotianV@163.com
* MMKV 存储
**/
public class KvUtil {
public static final String SCHOOL_ID = "SCHOOL_ID";//学校ID
private static KvUtil mKvUtil;
private static MMKV smMKV;
public static KvUtil getInstance() {
if (mKvUtil == null) {
synchronized (KvUtil.class) {
if (mKvUtil == null) {
mKvUtil = new KvUtil();
}
}
}
if (smMKV == null) {
smMKV = MMKV.defaultMMKV();
}
return mKvUtil;
}
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*/
public void encode(String key, Object object) {
if (object instanceof String) {
smMKV.encode(key, (String) object);
} else if (object instanceof Integer) {
smMKV.encode(key, (Integer) object);
} else if (object instanceof Boolean) {
smMKV.encode(key, (Boolean) object);
} else if (object instanceof Float) {
smMKV.encode(key, (Float) object);
} else if (object instanceof Long) {
smMKV.encode(key, (Long) object);
} else if (object instanceof Double) {
smMKV.encode(key, (Double) object);
} else if (object instanceof byte[]) {
smMKV.encode(key, (byte[]) object);
} else {
smMKV.encode(key, object.toString());
}
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*/
public Integer decodeInt(String key) {
return smMKV.decodeInt(key, 0);
}
public Double decodeDouble(String key) {
return smMKV.decodeDouble(key, 0.00);
}
public Long decodeLong(String key) {
return smMKV.decodeLong(key, 0L);
}
public Boolean decodeBoolean(String key) {
return smMKV.decodeBool(key, false);
}
public Float decodeFloat(String key) {
return smMKV.decodeFloat(key, 0F);
}
public byte[] decodeBytes(String key) {
return smMKV.decodeBytes(key);
}
public String decodeString(String key) {
return smMKV.decodeString(key, "");
}
public Set<String> decodeStringSet(String key) {
return smMKV.decodeStringSet(key, Collections.<String>emptySet());
}
public Parcelable decodeParcelable(String key) {
return smMKV.decodeParcelable(key, null);
}
//移除某个key对
public void removeValueForKey(String key) {
smMKV.removeValueForKey(key);
}
// 同时移除多个key对
public void removeValuesForKeys(String[] strings) {
smMKV.removeValuesForKeys(strings);
}
//清除所有key
public void clearAll() {
smMKV.clearAll();
}
}
Kotlin代码
/**
* @author :Create by Xia燚
* 时间:2022/7/4
* 邮箱:XiahaotianV@163.com
* MMKV 存储
**/
object KvUtil {
//运维人员名称
const val OPERATIONS_NAME ="operations_name"
var mmkv: MMKV? = null
init {
mmkv = MMKV.defaultMMKV()
}
fun put(key: String, value: Any?): Boolean {
return when (value) {
is String -> mmkv?.encode(key, value)!!
is Float -> mmkv?.encode(key, value)!!
is Boolean -> mmkv?.encode(key, value)!!
is Int -> mmkv?.encode(key, value)!!
is Long -> mmkv?.encode(key, value)!!
is Double -> mmkv?.encode(key, value)!!
is ByteArray -> mmkv?.encode(key, value)!!
else -> false
}
}
/**
* 这里使用安卓自带的Parcelable序列化,它比java支持的Serializer序列化性能好些
*/
fun <T : Parcelable> put(key: String, t: T?): Boolean {
if (t == null) {
return false
}
return mmkv?.encode(key, t)!!
}
fun put(key: String, sets: Set<String>?): Boolean {
if (sets == null) {
return false
}
return mmkv?.encode(key, sets)!!
}
fun getInt(key: String): Int? {
return mmkv?.decodeInt(key, 0)
}
fun getDouble(key: String): Double? {
return mmkv?.decodeDouble(key, 0.00)
}
fun getLong(key: String): Long? {
return mmkv?.decodeLong(key, 0L)
}
fun getBoolean(key: String): Boolean? {
return mmkv?.decodeBool(key, false)
}
fun getFloat(key: String): Float? {
return mmkv?.decodeFloat(key, 0F)
}
fun getByteArray(key: String): ByteArray? {
return mmkv?.decodeBytes(key)
}
fun getString(key: String): String? {
return mmkv?.decodeString(key, "")
}
/**
* SpUtils.getParcelable<Class>("")
*/
inline fun <reified T : Parcelable> getParcelable(key: String): T? {
return mmkv?.decodeParcelable(key, T::class.java)
}
fun getStringSet(key: String): Set<String>? {
return mmkv?.decodeStringSet(key, Collections.emptySet())
}
fun removeKey(key: String) {
mmkv?.removeValueForKey(key)
}
fun clearAll() {
mmkv?.clearAll()
}
}
MMKV 原理
内存准备
通过 mmap 内存映射文件,提供一段可供随时写入的内存块,App 只管往里面写数据,由操作系统负责将内存回写到文件,不必担心 crash 导致数据丢失。
数据组织
数据序列化方面我们选用 protobuf 协议,pb 在性能和空间占用上都有不错的表现。
写入优化
考虑到主要使用场景是频繁地进行写入更新,我们需要有增量更新的能力。我们考虑将增量 kv 对象序列化后,append 到内存末尾。