Introduction to the use of MMKV data storage components

Introduction to the use of MMKV data storage components

Introduction

MMKV is a WeChat open source key-value component based on mmap memory mapping. The underlying serialization/deserialization is implemented using protobuf, which has high performance and strong stability. It has been ported to Android/ macOS/ Win32/ POSIXplatform, together with open source.

GitHub address

advantage:

  1. Data encryption: In the Android environment, data encryption is very necessary. SP actually stores key-value pairs in local files for storage. If you need to encrypt data yourself to ensure data security, MMKV uses the AES CFB-128 algorithm to encrypt/decrypt.
  2. Multi-process sharing: SharedPreferences that comes with the system does not support multi-process. The existing implementation based on ContentProvider encapsulation, although multi-process is supported, but the performance is low, which often leads to ANR. Considering that mmap shared memory is inherently shared by multiple processes, MMKV digs into the capabilities of the Android system on this basis, and provides perhaps the most efficient multi-process data sharing component in the industry.
  3. Anonymous memory: On the basis of multi-process sharing, considering that some sensitive data (such as passwords) need to be shared between processes, but it is not convenient to store it in a file, it is not appropriate to directly use mmap. The Android system provides the ability of Ashmem to share memory anonymously, which will disappear after the process exits and will not land on the file, which is very suitable for this scenario. MMKV also provides Ashmem (anonymous shared memory) MMKV functions based on this.
  4. More efficient: MMKV uses protobuf for serialization and deserialization, which is more efficient than SP's xml storage method.
  5. Support migration from SP: If you used SP in your previous project and now want to use MMKV, you can migrate the previous SP implementation to MMKV with just a few lines of code.

principle

MMKV essentially mmaps the file into the memory block, and appends all the newly added key-values ​​to the memory; after reaching the boundary, it is rewritten and written back to make room. If the space is not enough, double memory space is used; For duplicate key values ​​that may exist in the memory file, MMKV only selects the last written value as the effective key value.

Core process:

  • Memory preparation

Through mmap memory-mapped files, a memory block that can be written at any time is provided. App only writes data into it, and the operating system is responsible for writing the memory back to the file, so there is no need to worry about crashes causing data loss.

  • Data organization

For data serialization, we use the protobuf protocol, and pb has a good performance in performance and space occupation.

  • Write optimization (emphasis)

Considering that the main use scenario is frequent write updates, we need the ability to incrementally update. We consider serializing the incremental kv object and append to the end of memory.

  • Space growth (emphasis)

Using append to achieve incremental updates brings a new problem, that is, if you keep appending, the file size will grow uncontrollably. We need to make a compromise between performance and space.

  • Data validity

Taking into account the instability of the file system and operating system, we have additionally added crc verification to screen invalid data. In the current iOS WeChat network environment, we observed that an average of about 700,000 daily data verification failed.

Supported data types

  • The following basic types of Java language are supported:
  • booleanintlongfloatdoublebyte[]
  • The following Java classes and containers are supported:
  • StringSet<String>
  • Any Parcelabletype that implements (serialization)

.

.

MMKV is simple to use

.

Add MMKV dependency

In the build.gradlefile add:

dependencies {
    
    
    implementation 'com.tencent:mmkv:1.2.7'
}

Initialize MMKV in Application

public void onCreate() {
    
    
    super.onCreate();
	
	//初始化MMKV组件
    String rootDir = MMKV.initialize(this);
	//打印MMKV文件的存放根目录(可以不写)
    System.out.println("mmkv root: " + rootDir);
}

CRUD operation of MMKV components

MMKV provides a global instance through which the API inside can be used to complete related operations

.

1. Add data

//获取MMKV的实例对象
MMKV kv = MMKV.defaultMMKV();

//向MMKV中添加Boolean类型的数据
kv.encode("bool", true);
System.out.println("bool: " + kv.decodeBool("bool"));

//向MMKV中添加Int类型的数据
kv.encode("int", Integer.MIN_VALUE);
System.out.println("int: " + kv.decodeInt("int"));

//向MMKV中添加Long类型的数据
kv.encode("long", Long.MAX_VALUE);
System.out.println("long: " + kv.decodeLong("long"));

//向MMKV中添加Dloat类型的数据
kv.encode("float", -3.14f);
System.out.println("float: " + kv.decodeFloat("float"));

//向MMKV中添加Double类型的数据
kv.encode("double", Double.MIN_VALUE);
System.out.println("double: " + kv.decodeDouble("double"));

//向MMKV中添加String类型的数据
kv.encode("string", "Hello from mmkv");
System.out.println("string: " + kv.decodeString("string"));

//向MMKV中添加Byte类型的数据
byte[] bytes = {
    
    'm', 'm', 'k', 'v'};
kv.encode("bytes", bytes);
System.out.println("bytes: " + new String(kv.decodeBytes("bytes")));

If different businesses need different storage, you can also create your own instances separately

MMKV mmkv = MMKV.mmkvWithID("MyID");
mmkv.encode("String", "萝莉");

If the business requires multi-process access, add the flag bit when initializing MMKV.MULTI_PROCESS_MODE

MMKV mmkv = MMKV.mmkvWithID("InterProcessKV", MMKV.MULTI_PROCESS_MODE);
mmkv.encode("String", "萝莉");

Note:
MMKV write logic is: when we cover a certain value, it does not immediately delete previous values will be retained, then each keyand valuehave storage restrictions, triggered when the storage limit, will delete , So that even if we cover frequently, it will not cause too much performance loss

2. Delete data

//获取MMKV的实例对象
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()));

3. Modify the data

Using the same keyre-add data again

4. Find data

According keyto find the correspondingvalue

//获取MMKV的实例对象
MMKV kv = MMKV.defaultMMKV();

boolean hasBool = kv.containsKey("bool");

.

.

Migrate from SharedPreferences

  • MMKV provides importFromSharedPreferences()functions can be more easily migrate data over.

  • MMKV also implements these two interfaces again SharedPreferences. SharedPreferences.EditorOnly two or three lines of code are required during migration, and other CRUD operation codes do not need to be changed.

//获取MMKV的实例对象
MMKV preferences = MMKV.mmkvWithID("myData");

//迁移旧数据
SharedPreferences old_man = getSharedPreferences("myData", MODE_PRIVATE);
preferences.importFromSharedPreferences(old_man);
old_man.edit().clear().commit();

.

.

MMKV advanced function introduction

1. Encryption

MMKV stores all key-values ​​in plain text by default, and relies on the sandbox mechanism of the Android system to ensure file encryption. If you are worried about information leakage, you can choose to encrypt MMKV

String cryptKey = "My-Encrypt-Key";
MMKV kv = MMKV.mmkvWithID("MyID", MMKV.SINGLE_PROCESS_MODE, cryptKey);

You can change the key, you can also change an encrypted MMKV to plain text, or vice versa

// 未加密的实例
MMKV kv = MMKV.mmkvWithID("MyID", MMKV.SINGLE_PROCESS_MODE, null);

//从未加密变为加密
kv.reKey("Key_seq_1");

//改变加密密钥
kv.reKey("Key_seq_2");

//从加密变为未加密
kv.reKey(null);

2. Customize the root directory

MMKV the files stored in the default $(FilesDir)/mmkv/directory. You can customize the root directory in Application

//文件路径
String dir = getFilesDir().getAbsolutePath() + "/mmkv_2";
//设置文件路径
String rootDir = MMKV.initialize(dir);
Log.i("MMKV", "mmkv root: " + rootDir);

It even supports customizing the directory of a certain file

String relativePath = getFilesDir().getAbsolutePath() + "/mmkv_3";
MMKV kv = MMKV.mmkvWithID("MyMMKVData", relativePath);

Note that the
official recommendation is to store the MMKV file in the private path of your App , not on the SD card. If you must do this, you should follow Android's scoped storage guidelines

3. Data Recovery

When crc verification fails or the file length is incorrect, MMKV will discard all data by default. You can let MMKV recover data.

Implement MMKVHandler interface

@Override
public MMKVRecoverStrategic onMMKVCRCCheckFail(String mmapID) {
    
    
    return MMKVRecoverStrategic.OnErrorRecover;
}

@Override
public MMKVRecoverStrategic onMMKVFileLengthError(String mmapID) {
    
    
    return MMKVRecoverStrategic.OnErrorRecover;
}

Note The
repair rate cannot be guaranteed, and strange key-values ​​may be repaired.

4. Native Buffer (local buffer)

Problems:

When taken from a MMKV Stringor byte[]when there will be a JVM from native to memory copy. If this value is immediately passed to another native library (JNI), there will be another memory copy from JVM to native. When this value is relatively large, the whole process will be very wasteful.

Solution:

Native Buffer is to solve this problem

int sizeNeeded = kv.getValueActualSize("bytes");

//创建本地缓存对象
NativeBuffer nativeBuffer = MMKV.createNativeBuffer(sizeNeeded);

if (nativeBuffer != null) {
    
    
    int size = kv.writeValueToNativeBuffer("bytes", nativeBuffer);
    Log.i("MMKV", "size Needed = " + sizeNeeded + " written size = " + size);

    // 将nativeBuffer传递给另一个本地库
    // ...

    // 完成后销毁
    MMKV.destroyNativeBuffer(nativeBuffer);
}

5. Log

MMKV prints logs to logcat by default, which is not convenient for locating and solving online problems. You can receive and forward MMKV logs when the App starts.

To implement the MMKVHandler interface, add code similar to the following:

@Override
public boolean wantLogRedirecting() {
    
    
    return true;
}

@Override
public void mmkvLog(MMKVLogLevel level, String file, int line, String func, String message) {
    
    
    String log = "<" + file + ":" + line + "::" + func + "> " + message;
    switch (level) {
    
    
        case LevelDebug:
            //Log.d("redirect logging MMKV", log);
            break;
        case LevelInfo:
            //Log.i("redirect logging MMKV", log);
            break;
        case LevelWarning:
            //Log.w("redirect logging MMKV", log);
            break;
        case LevelError:
            //Log.e("redirect logging MMKV", log);
            break;
        case LevelNone:
            //Log.e("redirect logging MMKV", log);
            break;
    }
}

Reference

MMKV For Android User Documentation

Guess you like

Origin blog.csdn.net/weixin_42324979/article/details/112168199