MMKV是基于mmap内存映射的key-value组件,底层序列化/反序列化使用protobuf实现,性能高,稳定性强,而且Android这边还支持多进程。
不管是单线程还是多线程模型下MMVK的效率都远超sp,sqllite甚至DataStore.
基本用法:
1:在App模块的build.gradle文件里添加:
implementation 'com.tencent:mmkv:1.2.14'
2:在Application里面初始化:
public void onCreate() {
super.onCreate();
String rootDir = MMKV.initialize(this);
System.out.println("mmkv root: " + rootDir);
}
CRUD 操作
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")));
可以看到,MMKV在使用上还是比较简单的。
删除 & 查询:
MMKV kv = MMKV.defaultMMKV();
kv.removeValueForKey("bool");
System.out.println("bool: " + kv.decodeBool("bool"));
kv.removeValuesForKeys(new String[]{"int", "long"});
System.out.println("allKeys: " + Arrays.toString(kv.allKeys()));
boolean hasBool = kv.containsKey("bool");
如果不是同业需要分区存储,也可以单独创建自己的实例:
MMKV kv = MMKV.mmkvWithID("MyID");
kv.encode("bool", true);
如果业务需要多进程访问,那么在刚开始化的时候加上标志位MMKV.MULTI_PROCESS_MODE:
MMKV kv = MMKV.mmkvWithID("InterProcessKV",MMKV.MULTI_PROCESS_MODE);
kv.encode("bool", true);
支持的数据类型
-
支持以下Java语言基础类型:
boolean、int、long、float、double、byte[]
-
支持以下Java类和容器:
String、Set<String>
- 任何发现
Parcelable
的类型
SharedPreferences 迁移
MMKV提供了importFromSharedPreferences()函数,可以比较方便地迁移数据过来。
MMKV还额外实现了一个遍SharedPreferences、SharedPreferences.Editor这两个界面,在迁移的时候只需要三行代码即可,其他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(); }
高级用法
封装MMKV
创建 Preferences.kt文件
package com.vvkj.mmkvdemo.utils import android.os.Parcelable import com.tencent.mmkv.MMKV import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty private inline fun <T> MMKV.delegate( key: String? = null, defaultValue: T, crossinline getter: MMKV.(String, T) -> T, crossinline setter: MMKV.(String, T) -> Boolean ): ReadWriteProperty<Any, T> = object : ReadWriteProperty<Any, T> { override fun getValue(thisRef: Any, property: KProperty<*>): T = getter(key ?: property.name, defaultValue) override fun setValue(thisRef: Any, property: KProperty<*>, value: T) { setter(key ?: property.name, value) } } fun MMKV.boolean( key: String? = null, defaultValue: Boolean = false ): ReadWriteProperty<Any, Boolean> = delegate(key, defaultValue, MMKV::decodeBool, MMKV::encode) fun MMKV.int(key: String? = null, defaultValue: Int = 0): ReadWriteProperty<Any, Int> = delegate(key, defaultValue, MMKV::decodeInt, MMKV::encode) fun MMKV.long(key: String? = null, defaultValue: Long = 0L): ReadWriteProperty<Any, Long> = delegate(key, defaultValue, MMKV::decodeLong, MMKV::encode) fun MMKV.float(key: String? = null, defaultValue: Float = 0.0F): ReadWriteProperty<Any, Float> = delegate(key, defaultValue, MMKV::decodeFloat, MMKV::encode) fun MMKV.double(key: String? = null, defaultValue: Double = 0.0): ReadWriteProperty<Any, Double> = delegate(key, defaultValue, MMKV::decodeDouble, MMKV::encode) private inline fun <T> MMKV.nullableDefaultValueDelegate( key: String? = null, defaultValue: T?, crossinline getter: MMKV.(String, T?) -> T, crossinline setter: MMKV.(String, T) -> Boolean ): ReadWriteProperty<Any, T> = object : ReadWriteProperty<Any, T> { override fun getValue(thisRef: Any, property: KProperty<*>): T = getter(key ?: property.name, defaultValue) override fun setValue(thisRef: Any, property: KProperty<*>, value: T) { setter(key ?: property.name, value) } } fun MMKV.byteArray( key: String? = null, defaultValue: ByteArray? = null ): ReadWriteProperty<Any, ByteArray> = nullableDefaultValueDelegate(key, defaultValue, MMKV::decodeBytes, MMKV::encode) fun MMKV.string(key: String? = null, defaultValue: String? = null): ReadWriteProperty<Any, String> = nullableDefaultValueDelegate(key, defaultValue, MMKV::decodeString, MMKV::encode) fun MMKV.stringSet( key: String? = null, defaultValue: Set<String>? = null ): ReadWriteProperty<Any, Set<String>> = nullableDefaultValueDelegate(key, defaultValue, MMKV::decodeStringSet, MMKV::encode) inline fun <reified T : Parcelable> MMKV.parcelable( key: String? = null, defaultValue: T? = null ): ReadWriteProperty<Any, T> = object : ReadWriteProperty<Any, T> { override fun getValue(thisRef: Any, property: KProperty<*>): T = decodeParcelable(key ?: property.name, T::class.java, defaultValue) override fun setValue(thisRef: Any, property: KProperty<*>, value: T) { encode(key ?: property.name, value) } }
调用方法:
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.tanjiajun.mmkvdemo.R
import com.tanjiajun.mmkvdemo.data.model.UserData
import com.tanjiajun.mmkvdemo.utils.*
import com.tencent.mmkv.MMKV
class MainActivity : AppCompatActivity() {
private val mmkv: MMKV by lazy { MMKV.defaultMMKV() }
private var boolean by mmkv.boolean(key = "boolean", defaultValue = false)
private var int by mmkv.int(key = "int", defaultValue = 0)
private var long by mmkv.long("long", 0L)
private var float by mmkv.float(key = "float", defaultValue = 0.0F)
private var double by mmkv.double(key = "double", defaultValue = 0.0)
private var byteArray by mmkv.byteArray(key = "byteArray")
private var string by mmkv.string(key = "string")
private var stringSet by mmkv.stringSet(key = "stringSet")
private var parcelable by mmkv.parcelable<UserData>("parcelable")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
boolean = true
int = 100
long = 100L
float = 100F
double = 100.0
byteArray = ByteArray(100).apply {
for (i in 0 until 100) {
set(i, i.toByte())
}
}
string = "李书生"
stringSet = HashSet<String>().apply {
for (i in 0 until 100) {
add("第($i)个")
}
}
parcelable = UserData(name = "李书生", gender = "男", age = 26)
Log.i(TAG, "boolean:$boolean")
Log.i(TAG, "int:$int")
Log.i(TAG, "long:$long")
Log.i(TAG, "float:$float")
Log.i(TAG, "double:$double")
Log.i(TAG, "byteArray:$byteArray")
Log.i(TAG, "string:$string")
Log.i(TAG, "stringSet:$stringSet")
Log.i(TAG, "parcelable:$parcelable")
}
private companion object {
const val TAG = "Lishusheng"
}
}
网友评论