2.MMKV的基本使用

概述

         MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。从 2015 年中至今在微信上使用,其性能和稳定性经过了时间的验证。    GitHub地址:https://github.com/Tencent/MMKV

MMKV原理

        1)内存准备:通过 mmap 内存映射文件,提供一段可供随时写入的内存块,App 只管往里面写数据,由操作系统负责将内存回写到文件,不必担心 crash 导致数据丢失。

       2)数据组织:数据序列化方面我们选用 protobuf 协议,pb 在性能和空间占用上都有不错的表现。

       3)写入优化:考虑到主要使用场景是频繁地进行写入更新,我们需要有增量更新的能力。我们考虑将增量 kv 对象序列化后,append 到内存末尾。

       4)空间增长:使用 append 实现增量更新带来了一个新的问题,就是不断 append 的话,文件大小会增长得不可控。我们需要在性能和空间上做个折中。

1. Android中使用

     1.1 添加依赖

    ​dependencies {
        implementation 'com.tencent:mmkv-static:1.2.2''
    }

     1.2 初始化

       MMKV 的使用非常简单,所有变更立马生效,无需调用 syncapply。 在 App 启动时初始化 MMKV,设定 MMKV 的根目录(files/mmkv/),例如在 Application 里:

   public class MyApp extends Application {
    private static final String TAG = MyApp.class.getSimpleName();
    @Override
    public void onCreate() {
        super.onCreate();
        String rootDir = MMKV.initialize(this);
        Log.i(TAG,"mmkv root: " + rootDir);
    }
}

      1.3 CRUD 操作

       1)MMKV 提供一个全局的实例,可以直接使用:

import com.tencent.mmkv.MMKV;
...
MMKV kv = MMKV.defaultMMKV();
 
kv.encode("bool", true);
System.out.println("bool: " + kv.decodeBool("bool"));
 
kv.encode("int", Integer.MIN_VALUE);
System.out.println("int: " + kv.decodeInt("int"));
 
kv.encode("long", Long.MAX_VALUE);
System.out.println("long: " + kv.decodeLong("long"));
 
kv.encode("float", -3.14f);
System.out.println("float: " + kv.decodeFloat("float"));
 
kv.encode("double", Double.MIN_VALUE);
System.out.println("double: " + kv.decodeDouble("double"));
 
kv.encode("string", "Hello from mmkv");
System.out.println("string: " + kv.decodeString("string"));
 
byte[] bytes = {'m', 'm', 'k', 'v'};
kv.encode("bytes", bytes);
System.out.println("bytes: " + new String(kv.decodeBytes("bytes")));

      2)删除与查询

MMKV kv = MMKV.defaultMMKV();
 
// 移除指定的key
kv.removeValueForKey("bool");
System.out.println("bool: " + kv.decodeBool("bool"));
    
// 移除一组key
kv.removeValuesForKeys(new String[]{"int", "long"});
System.out.println("allKeys: " + Arrays.toString(kv.allKeys()));
 
boolean hasBool = kv.containsKey("bool");

      3)如果不同业务需要区别存储,也可以单独创建自己的实例:

MMKV mmkv = MMKV.mmkvWithID("MyID");
mmkv.encode("bool", true);

     4)如果业务需要多进程访问,那么在初始化的时候加上标志位 MMKV.MULTI_PROCESS_MODE

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

     1.4 支持的数据类型


       1)支持一下Java语言基础类型:

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

       2)支持一下Java类和容器:

       String、Set<String>、任何实现了Parcelable的类型。

    1.5 SharedPreferences 迁移


       1) MMKV 提供了 importFromSharedPreferences() 函数,可以比较方便地迁移数据过来。

       2)MMKV 还额外实现了一遍 SharedPreferences、SharedPreferences.Editor 这两个 interface,在迁移的时候只需两三行代码即可,其他 CRUD 操作代码都不用改

    private void testImportSharedPreferences() {
        //SharedPreferences preferences = getSharedPreferences("myData", MODE_PRIVATE);
        MMKV preferences = MMKV.mmkvWithID("myData");
        // 迁移旧数据
        {
            SharedPreferences old_man = getSharedPreferences("myData", MODE_PRIVATE);
            preferences.importFromSharedPreferences(old_man);
            old_man.edit().clear().commit();
        }
        // 跟以前用法一样
        SharedPreferences.Editor editor = preferences.edit();
        editor.putBoolean("bool", true);
        editor.putInt("int", Integer.MIN_VALUE);
        editor.putLong("long", Long.MAX_VALUE);
        editor.putFloat("float", -3.14f);
        editor.putString("string", "hello, imported");
        HashSet<String> set = new HashSet<String>();
        set.add("W"); set.add("e"); set.add("C"); set.add("h"); set.add("a"); set.add("t");
        editor.putStringSet("string-set", set);
        // 无需调用 commit()
        //editor.commit();
    }

上一篇:交换排序(c++)


下一篇:Ceph性能瓶颈分析与优化(混合盘篇)