欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 八卦 > 【MMKV】HarmonyOS中的优秀轻量化存储方式

【MMKV】HarmonyOS中的优秀轻量化存储方式

2025/2/21 3:55:18 来源:https://blog.csdn.net/2301_79624024/article/details/144175504  浏览:    关键词:【MMKV】HarmonyOS中的优秀轻量化存储方式

MMKV

引言

在移动应用开发的世界里,数据存储和管理是至关重要的一环。随着技术的不断进步,开发者们对于高性能、轻量级、易用的数据存储解决方案的需求日益增长。MMKV(Memory Mapped Key-Value)正是这样一个开源的高性能key-value存储框架,它以其独特的优势在移动应用开发领域中占据了一席之地。

MMKV的出现,为开发者们提供了一个全新的选择。它不仅具备高性能、轻量级、易用性等特点,还支持多种数据类型,适用于Android、iOS以及HarmonyOS平台。无论是存储用户配置信息、缓存数据,还是在多进程环境下的数据共享,MMKV都能发挥出其卓越的性能优势。

然而,MMKV并非完美无缺。它的功能相对简单,不支持复杂的查询和分析操作,也不支持跨进程共享数据和网络同步。这就要求开发者在使用MMKV时,需要根据具体的应用场景和需求,权衡其优势和局限性,选择最合适的存储方式。

在接下来的内容中,我们将深入探讨MMKV的工作原理、安装方法、实际应用以及一些高级特性,帮助您更好地理解和使用这个强大的存储框架。

概述

MMKV(Memory Mapped Key-Value)是一个开源的高性能key-value存储框架,主要用于移动端应用的数据存储和管理。它具有轻量级、高性能、易用性等特点,适用于Android和iOS以及HarmonyOS平台。MMKV的特点包括:

  1. 高性能:MMKV 使用 mmap 使内存与文件保持同步,使用 protobuf 对值进行编码/解码,从而充分利用本机平台实现最佳性能。
    • 多进程并发:MMKV 支持进程间并发读读和读写访问。
  2. 轻量级
    • 少量文件:MMKV 包含进程锁、编码/解码辅助程序和 mmap 逻辑,仅此而已。它真的很整洁。
    • 大约 600K 的二进制大小:MMKV 在应用程序大小上为每个架构增加大约 600K,而压缩后 (HAR/HAP) 则少得多。
  3. 易用性:提供了简洁的API,方便开发者进行数据的读写操作,您可以随心所欲地使用 MMKV。所有更改都会立即保存,不需要,不需要调用。sync``flush
  4. 支持多种数据类型:可以存储基本数据类型、字符串、字节数组等数据。

优势

  1. 高性能:MMKV在性能上有很大优势,读写速度快,适合大规模数据存储和高并发访问。
  2. 内存映射:MMKV使用内存映射技术,可以直接将数据映射到内存中,提高了读写效率。
  3. 跨平台:MMKV支持Android和iOS平台,且提供了相似的API,方便开发者在不同平台上使用。

缺点

  1. 功能相对简单:相比较其他一些存储方案,MMKV的功能相对简单,不支持复杂的查询和分析操作。
  2. 不支持跨进程:MMKV不支持跨进程共享数据,这在一些场景下可能会有限制。
  3. 不支持网络同步:MMKV不支持网络同步,需要开发者自行处理数据同步的问题。

工作原理

MMKV的核心原理是内存映射。内存映射文件是一种将文件或磁盘块映射到内存的技术,使得读写文件就像读写内存一样。MMKV使用了mmap函数来实现内存映射,该函数是Linux提供的一种应用级内存映射工具。通过内存映射,MMKV可以大大提高读写性能,同时减少了内存拷贝和上下文切换的开销。

开始

安装

  1. 通过 OHPM(推荐):
  • 这是将 MMKV 添加到项目中的最快、最推荐的方法。
ohpm install @tencent/mmkv

或者手动将其添加到您的项目中

  • 将以下行添加到您的 app 模块上。oh-package.json5
"dependencies": {"@tencent/mmkv": "2.0.0",
}
  • 然后运行
ohpm install
  1. 通过来源

您可以按源集成 MMKV。

  • 查看 MMKV 源代码:

    git clone https://github.com/Tencent/MMKV.git
    

    注意

    • 您可以考虑将 MMKV 添加为 git 子模块。
    • 默认情况下,MMKV 以静态方式链接。如果您想要更小的二进制大小并且您知道自己在做什么,您可以编辑 MMKV 模块的文件,将行更改为 、 和 。libc++``build-profile.json5``"arguments": "-DOHOS_STL=c++_shared"``"cppFlags": "-DMMKV_STL_SHARED=1
    • 如果要直接访问 MMKV 的 C++ 接口,可以编辑 MMKV 模块的文件,将行改为 .请注意,这将稍微增加二进制文件的大小。build-profile.json5``"cppFlags": "…… -fvisibility=default ……"
  • 将以下行添加到您的 app 模块上。oh-package.json5

    "dependencies": {"@tencent/mmkv": "file:path/to/mmkv/OpenHarmony/MMKV",
    }
    
  • 然后运行

    ohpm install
    
通过预构建的 HAR(不推荐):

您可以通过预构建的 HAR 集成 MMKV。

  • 查看 MMKV 源代码:

    git clone https://github.com/Tencent/MMKV.git
    
  • 在 中打开 MMKV 项目,打开 Product 窗口,然后选择 Build Mode 到 “release”;选择 module,在菜单中选择 -> ,将构建结果作为 “MMKV.har” 导出到您的项目文件夹。path/to/mmkv/OpenHarmony``MMKV``Build``Make Module 'MMKV'

    • 您可以考虑将 MMKV 添加为 git 子模块。
    • 默认情况下,MMKV 以静态方式链接。如果您想要更小的二进制大小并且您知道自己在做什么,您可以编辑 MMKV 模块的文件,将行更改为 、 和 。libc++``build-profile.json5``"arguments": "-DOHOS_STL=c++_shared"``"cppFlags": "-DMMKV_STL_SHARED=1
    • 如果要直接访问 MMKV 的 C++ 接口,可以编辑 MMKV 模块的文件,将行改为 .请注意,这将稍微增加二进制文件的大小。build-profile.json5``"cppFlags": "…… -fvisibility=default ……"
  • 将以下行添加到您的 app 模块上。oh-package.json5

    "dependencies": {"@tencent/mmkv": "file:path/to/MMKV.har",
    }
    
  • 然后运行

    ohpm install
    

实际应用

MMKV适用于移动应用开发中的各种场景,如替代Preferences存储用户配置信息、缓存数据等。在实际应用中,开发者需要根据具体场景和需求来选择合适的存储方式,并结合MMKV的特点来优化应用的性能和稳定性。

通过 OHPM 安装:

ohpm install @tencent/mmkv

设置

您可以随心所欲地使用 MMKV。所有更改都会立即保存,不需要,无需调用。
在 App 启动时设置 MMKV,比如您的函数,添加以下几行:sync``apply``EntryAbility.onCreate()

import { MMKV } from '@tencent/mmkv';export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {let appCtx = this.context.getApplicationContext();let mmkvRootDir = MMKV.initialize(appCtx);console.info('mmkv rootDir: ', mmkvRootDir);……}
  • MMKV 有一个全局实例,可以直接使用:

    import { MMKV } from '@tencent/mmkv';let mmkv = MMKV.defaultMMKV();
    mmkv.encodeBool('bool', true);
    console.info('bool = ', mmkv.decodeBool('bool'));mmkv.encodeInt32('int32', Math.pow(2, 31) - 1);
    console.info('max int32 = ', mmkv.decodeInt32('int32'));mmkv.encodeInt64('int', BigInt(2**63) - BigInt(1));
    console.info('max int64 = ', mmkv.decodeInt64('int'));let str: string = 'Hello OpenHarmony from MMKV';
    mmkv.encodeString('string', str);
    console.info('string = ', mmkv.decodeString('string'));
    
  • 删除和查询

    mmkv.removeValueForKey('bool');
    console.info('contains "bool"', mmkv.containsKey('bool'));mmkv.removeValuesForKeys(['int32', 'int']);
    console.info('all keys: ', mmkv.allKeys().join());
    

    如果不同的 module/logic 需要隔离存储,也可以单独创建自己的 MMKV 实例:

    var mmkv = MMKV.mmkvWithID('test');
    mmkv.encodeBool('bool', true);
    console.info('bool = ', mmkv.decodeBool('bool'));
    

    如果需要多进程访问,可以在 MMKV 初始化时设置:MMKV.MULTI_PROCESS_MODE

    var mmkv = MMKV.mmkvWithID('test-multi-process', MMKV.MULTI_PROCESS_MODE);
    mmkv.encodeBool('bool', true);
    console.info('bool = ', mmkv.decodeBool('bool'));
    

支持的类型

  • 基元类型:

    boolean, number, bigint, string

  • 类别和收藏:

    boolean[], number[], string[], ArrayBuffer

  • 自定义类:
    我们不直接支持自定义类,因为 OHOS 中没有替代类。您可以先编码/解码为 JSON。或者使用您喜欢的任何编码库,例如 protobuf。Parcel

    let user = {username: 'dummy_user',age: 23
    }// 将对象序列化为一个JSON字符串。
    mmkv.encodeString('user', JSON.stringify(user))// 将JSON字符串反序列化为对象。
    let jsonUser = mmkv.decodeString('user') // { 'username': 'dummy_user', 'age': 23 }
    let userObject = JSON.parse(jsonUser)
    

日志

  • 默认情况下,MMKV 将 log 打印到 hilog 中,这不方便诊断在线问题。 您可以在 MMKV 的本机接口上设置 MMKV 日志重定向。 查看如何在 C++ 上执行此操作。 由于 NAPI 运行时的当前限制,我们无法有效地将日志重定向到 JavaScript 端。

  • 您可以在初始化时一劳永逸地关闭 MMKV 的日志记录(我们强烈建议不要这样做)。

    import { MMKV, MMKVLogLevel } from '@tencent/mmkv';MMKV.initialize(appCtx, MMKVLogLevel.None);
    

加密

  • 默认情况下,MMKV 将所有键值以纯文本形式存储在文件中,依靠 Android/iOS 的沙盒来确保文件已加密。如果您担心信息泄露,您可以选择加密 MMKV。

    let encryptKey = 'MyEncryptKey';
    let mmkv = MMKV.mmkvWithID('test-encryption', MMKV.SINGLE_PROCESS_MODE, encryptKey);
    
  • 您可以稍后根据需要更改加密密钥。您还可以将现有 MMKV 实例从加密更改为未加密,反之亦然。

    // 未加密的 MMKV 实例
    let mmkv = MMKV.mmkvWithID('test-encryption');// 从未加密更改为加密
    mmkv.reKey('Key_seq_1');// 更改加密密钥
    mmkv.reKey('Key_seq_2');// 从加密更改为未加密
    kmmkv.reKey();
    

自定义位置

  • 默认情况下,MMKV 将文件存储在 .你可以在 App 启动时自定义 MMKV 的根目录$(FilesDir)/mmkv/

    let appCtx = this.context.getApplicationContext();
    let rootDir = appCtx.filesDir + '/mmkv_2';
    let cacheDir = appCtx.cacheDir;
    MMKV.initializeWithPath(rootDir, cacheDir);
    
  • 您甚至可以自定义任何 MMKV 实例的位置:

    let appCtx = this.context.getApplicationContext();
    let rootDir = appCtx.filesDir + '/mmkv_3';
    var mmkv = MMKV.mmkvWithID('testCustomDir', MMKV.SINGLE_PROCESS_MODE, null, rootDir);
    

    注意:建议将 MMKV 文件存储在应用的沙盒路径不要将它们存储在外部存储设备(又名 SD 卡)上。

原生缓冲区

  • 通常,当 or 值从 MMKV 获取时,会有一个内存从 **native 复制到 JSVM。**如果该值立即传递给另一个本机库 (NAPI),则会发生另一次从 JSVM 到本机的内存复制。如果该值的大小很大,则整个过程会浪费太多。Native Buffer 来了。
    Native Buffer 是用 native 创建的内存缓冲区,包装方式与 JavaScript 一样,可以透明地传递给另一个 native 库。此过程节省了向JSVM复制的内存。示例代码:string``ArrayBuffer``NativeBuffer

    let sizeNeeded = mmkv.getValueSize('bytes', true);
    let nativeBuffer = MMKV.createNativeBuffer(sizeNeeded);
    if (nativeBuffer != null) {let size = mmkv.writeValueToNativeBuffer('bytes', nativeBuffer);console.info('NativeBuffer: size Needed = ', sizeNeeded, ',  written size = ', size);// 将 nativeBuffer 传递给另一个原生库// ...// 完成后销毁MMKV.destroyNativeBuffer(nativeBuffer);
    }
    

备份和恢复

  • 您可以使用MMKV的备份和恢复API将数据备份到其他地方,然后再恢复它们。

    let rootDir = ...;
    let backupRootDir = rootDir + '/mmkv_backup';
    // 备份 1 实例
    let ret = MMKV.backupOneToDirectory(mmapID, backupRootDir);
    // 备份所有实例
    let count = MMKV.backupAllToDirectory(backupRootDir);
    // 还原 1 个实例
    ret = MMKV.restoreOneMMKVFromDirectory(mmapID, backupRootDir);
    // 还原所有实例
    count = MMKV.restoreAllFromDirectory(backupRootDir);
    

自动过期

  • 您可以将 MMKV 升级为自动密钥过期。请注意,这是一项重大更改。升级到自动密钥过期后,该文件对于任何旧版本的 MMKV (<= v1.2.16) 都无效,无法正常运行。

  • 全局过期时间。最简单的方法是为整个文件中的所有键开启自动密钥过期。

    // 一天后过期
    mmkv.enableAutoKeyExpire(MMKV.ExpireInDay); // MMKV.ExpireInDay = 24 * 60 * 60
    

    或者,如果您愿意,可以启用自动密钥过期,而无需设置全局过期持续时间。在这种情况下,默认情况下每个密钥都不会过期。

    // 启用无全局持续时间的自动密钥过期
    mmkv.enableAutoKeyExpire(MMKV.ExpireNever); // MMKV.ExpireNever = 0
    
  • 个人到期日。您可以为密钥设置特殊的过期持续时间,无论文件是否具有全局持续时间。请注意,您必须先启用自动密钥过期

    // 启用持续时间为一小时的自动密钥过期
    mmkv.enableAutoKeyExpire(MMKV.ExpireInHour); // MMKV.ExpireInHour = 60 * 60// 设置一个具有文件全局过期持续时间的键,即 MMKV.ExpireInHour
    mmkv.encodeString('key_1', 'some value');// 设置一个 2 小时后过期的特殊密钥
    mmkv.encodeString('key_2', 'some value', 2 * 60 * 60);// 设置永不过期的特殊密钥
    mmkv.encodeString('key_3', 'some value', MMKV.ExpireNever);
    

    或者,如果您愿意,可以启用自动密钥过期,而无需设置全局过期持续时间。在这种情况下,默认情况下每个密钥都不会过期。

    // 启用无全局持续时间的自动密钥过期
    mmkv.enableAutoKeyExpire(MMKV.ExpireNever); // MMKV.ExpireNever = 0// 设置永不过期的密钥
    mmkv.encodeString('key_1', 'some value');// 设置一个 1 小时后过期的特殊密钥
    mmkv.encodeString('key_2', 'some value', MMKV.ExpireInHour);
    
  • 过期持续时间以秒为单位。为方便起见,MMKV 有一些预定义的持续时间。您可以使用您喜欢的任何其他持续时间。例如,一周后的过期时间为 。7 * 24 * 60 * 60

    static const int ExpireNever = 0;
    static const int ExpireInMinute = 60;
    static const int ExpireInHour = 60 * 60;
    static const int ExpireInDay = 24 * 60 * 60;
    static const int ExpireInMonth = 30 * 24 * 60 * 60;
    static const int ExpireInYear = 365 * 30 * 24 * 60 * 60;
    

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词