我们很愉快地提供了 Ashmem MMKV 的功能。
- 数据加密
不像 iOS 提供了硬件层级的加密机制,在 Android 环境里,数据加密是非常必须的。
MMKV 使用了 AES CFB-128 算法来加密/解密。我们选择 CFB 而不是常见的 CBC 算法,
主要是因为 MMKV 使用 append-only 实现插入/更新操作,流式加密算法更加合适。
- 数据有效性
1.3性能对比
我们将 MMKV 和 SharedPreferences、SQLite 进行对比, 重复读写操作 1k 次。相关测试代码在 Android/MMKV/mmkvdemo/。结果如下图表。
单进程性能
可见,MMKV 在写入性能上远远超越 SharedPreferences & SQLite,在读取性能上也有相近或超越的表现。
可见,MMKV 无论是在写入性能还是在读取性能,都远远超越 MultiProcessSharedPreferences & SQLite & SQLite, MMKV 在 Android 多进程 key-value 存储组件上是不二之选。
1.3 MMKV 原理
-
内存准备 通过 mmap 内存映射文件,提供一段可供随时写入的内存块,App 只管往里面写数据,由操作系统负责将内存回写到文件,不必担心 crash 导致数据丢失。
-
数据组织 数据序列化方面我们选用 protobuf 协议,pb 在性能和空间占用上都有不错的表现。
-
写入优化 考虑到主要使用场景是频繁地进行写入更新,我们需要有增量更新的能力。我们考虑将增量 kv 对象序列化后,append 到内存末尾。 这样同一个 key 会有新旧若干份数据,最新的数据在最后;那么只需在程序启动第一次打开 mmkv 时,不断用后读入的 value 替换之前的值,就可以保证数据是最新有效的。
-
空间增长 使用 append 实现增量更新带来了一个新的问题,就是不断 append 的话,文件大小会增长得不可控。我们需要在性能和空间上做个折中。 以内存 pagesize 为单位申请空间,在空间用尽之前都是 append 模式;当 append 到文件末尾时,进行文件重整、key 排重,尝试序列化保存排重结果; 排重后空间还是不够用的话,将文件扩大一倍,直到空间足够。
-
数据有效性 考虑到文件系统、操作系统都有一定的不稳定性,我们另外增加了 crc 校验,对无效数据进行甄别。
更详细的设计原理参考 MMKV 原理。
1.4 快速上手
dependencies {
implementation ‘com.tencent:mmkv:1.0.23’
// replace “1.0.23” with any available version
}
MMKV的使用非常简单, 所有变更立马生效,无需调用 sync、apply。 在 App 启动时初始化 MMKV,设定 MMKV 的根目录 (默认/data/data/xxx.xxx/files/mmkv/) (sp存储在/data/data/xxx.xxx/shared_prefs/)
支持从SP迁移数据importFromSharedPreferences
MMKV 还额外实现了一遍 SharedPreferences、SharedPreferences.Editor 这两个 interface
// 可以跟SP用法一样
SharedPreferences.Editor editor = mmkv.edit();
// 无需调用 commit()
//editor.commit();
MMKV 的使用非常简单,所有变更立马生效,无需调用 sync、apply。 在 App 启动时初始化 MMKV,设定 MMKV 的根目录(files/mmkv/),例如在 MainActivity 里:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String rootDir = MMKV.initialize(this);
System.out.println("mmkv root: " + rootDir);
//……
}
MMKV 提供一个全局的实例,可以直接使用:
import com.tencent.mmkv.MMKV;
//……
MMKV kv = MMKV.defaultMMKV();
kv.encode(“bool”, true);
boolean bValue = kv.decodeBool(“bool”);
kv.encode(“int”, Integer.MIN_VALUE);
int iValue = kv.decodeInt(“int”);
kv.encode(“string”, “Hello from mmkv”);
String str = kv.decodeString(“string”);
使用完毕的几个方法
public native void clearAll();
// MMKV’s size won’t reduce after deleting key-values
// call this method after lots of deleting f you care about disk usage
// note that clearAll
has the similar effect of trim
public native void trim();
// call this method if the instance is no longer needed in the near future
// any subsequent call to the instance is undefined behavior
public native void close();
// call on memory warning
// any subsequent call to the instance will load all key-values from file again
public native void clearMemoryCache();
// you don’t need to call this, really, I mean it
// unless you care about out of battery
public void sync() {
sync(true);
}
1.5 补充适用建议
如果使用请务必做code19版本的适配,这个在github官网有说明
依赖下面这个库,然后对19区分处理
implementation ‘com.getkeepsafe.relinker:relinker:1.3.1’
if (android.os.Build.VERSION.SDK_INT == 19) {
MMKV.initialize(relativePath, new MMKV.LibLoader() {
@Override
public void loadLibrary(String libName) {
ReLinker.loadLibrary(context, libName);
}
});
} else {
MMKV.initialize(context);
}
1.6 限制
可看到,一个键会存入多分实例,最后存入的就是最新的。
MMKV 在大部分情况下都性能强劲,key/value 的数量和长度都没有限制。
然而 MMKV 在内存里缓存了所有的 key-value,在总大小比较大的情况下(例如 100M+),App 可能会爆内存,触发重整回写时,写入速度也会变慢。
支持大文件的 MMKV 正在开发中,有望在下一个大版本发布。
1.7 多进程使用
1.7.1锁 lock unlock tryLock
注意如果一个进程lock住,另一个进程mmkvWithID获取MMKV时就阻塞住,直到持有进程释放。
// get the lock immediately
MMKV mmkv2 = MMKV.mmkvWithID(LOCK_PHASE_2, MMKV.MULTI_PROCESS_MODE);
mmkv2.lock();
Log.d(“locked in child”, LOCK_PHASE_2);
Runnable waiter = new Runnable() {
@Override
public void run() {
//阻塞住 直到其他进程释放
MMKV mmkv1 = MMKV.mmkvWithID(LOCK_PHASE_1, MMKV.MULTI_PROCESS_MODE);
mmkv1.lock();
Log.d(“locked in child”, LOCK_PHASE_1);
}
};
注意:如果其他进程有进行修改,不会立即触发onContentChangedByOuterProcess,
checkLoadData如果变化,会clearMemoryState,重新loadFromFile。//数据量大时不要太频繁
读取decodeXXX会阻塞住,先回调onContentChangedByOuterProcess,再返回值,保证值是最新的。
1.7.2 mmkvWithAshmemID 匿名共享内存
可以进行进程间通信,可设置pageSize
// a memory only MMKV, cleared on program exit
// size cannot change afterward (because ashmem won’t allow it)
1.7.3 测试结果
write速度: mmkv > cryptKV >> sp
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
s2eB-1715893691641)]
[外链图片转存中…(img-pARSlHVy-1715893691643)]
[外链图片转存中…(img-E9dLPUoz-1715893691645)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!