介绍
MMKV 的使用非常简单,所有变更立马生效,无需调用 sync
、apply
安装引入
注:从 v2.0.0 起, MMKV去掉了 32-bit 架构的支持、API level 22 及以下的支持, 如有这类需求,请使用 v1.3.x LTS 版本
dependencies {
implementation 'com.tencent:mmkv:1.3.11'
}
初始化
文中提供两种初始化方式,任选其一即可,推荐使用默认
class App : Application() {
override fun onCreate() {
super.onCreate()
//默认初始化
//数据存储目录: /data/data/包名/files
MMKV.initialize(this)
//修改存储目录的初始化
//数据存储目录:/data/data/包名/files/mmkv
val path = filesDir.absolutePath + "/mmkv"
MMKV.initialize(path)
}
}
正常实例化
// 获取默认的全局实例
val kv = MMKV.defaultMMKV()
kv!!.encode("key", "data") // 写入(key为任意字符串)
kv.decodeString("key", "") // 读取(需和写入的key保持一致)
// 根据业务区别存储, 附带一个自己的 ID
MMKV.mmkvWithID("ID_")
// 多进程同步支持
MMKV.mmkvWithID("ID_", MMKV.MULTI_PROCESS_MODE)
数据迁移
根据自己的业务需求进行,此方法只为使用介绍,非必须
val kv = MMKV.mmkvWithID("ID_")
val oldData = getSharedPreferences("ID_", MODE_PRIVATE)
// 迁移旧数据
kv!!.importFromSharedPreferences(oldData);
// 清空旧数据
oldData.edit().clear().apply()
优雅封装
import android.os.Parcelable
import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.tencent.mmkv.MMKV
import kotlinx.coroutines.flow.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
interface IMMKVOwner {
val mmapID: String
val kv: MMKV
}
open class MMKVOwner(override val mmapID: String) : IMMKVOwner {
override val kv: MMKV by lazy { MMKV.mmkvWithID(mmapID) }
}
fun IMMKVOwner.mmkvInt(default: Int = 0) =
MMKVProperty({ kv.decodeInt(it, default) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvLong(default: Long = 0L) =
MMKVProperty({ kv.decodeLong(it, default) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvBool(default: Boolean = false) =
MMKVProperty({ kv.decodeBool(it, default) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvFloat(default: Float = 0f) =
MMKVProperty({ kv.decodeFloat(it, default) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvDouble(default: Double = 0.0) =
MMKVProperty({ kv.decodeDouble(it, default) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvString() =
MMKVProperty({ kv.decodeString(it) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvString(default: String) =
MMKVProperty({ kv.decodeString(it) ?: default }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvStringSet() =
MMKVProperty({ kv.decodeStringSet(it) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvStringSet(default: Set<String>) =
MMKVProperty({ kv.decodeStringSet(it) ?: default }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvBytes() =
MMKVProperty({ kv.decodeBytes(it) }, { kv.encode(first, second) })
fun IMMKVOwner.mmkvBytes(default: ByteArray) =
MMKVProperty({ kv.decodeBytes(it) ?: default }, { kv.encode(first, second) })
inline fun <reified T> IMMKVOwner.mmkvList(
default: List<T> = emptyList()
): ReadWriteProperty<IMMKVOwner, List<T>> {
val type = object : TypeToken<List<T>>() {}.type
val gson = Gson()
return MMKVProperty(
decode = { key ->
kv.decodeString(key)?.takeIf { it.isNotBlank() }
?.let { gson.fromJson(it, type) }
?: default
},
encode = {
kv.encode(first, gson.toJson(second, type))
}
)
}
inline fun <reified T> IMMKVOwner.mmkvJsonObject(
default: T
): ReadWriteProperty<IMMKVOwner, T> {
return MMKVProperty(
decode = { key ->
kv.decodeString(key)?.let {
Json.decodeFromString<T>(it)
} ?: default
},
encode = {
kv.encode(first, Json.encodeToString(second))
}
)
}
inline fun <reified T : Parcelable> IMMKVOwner.mmkvParcelable() =
MMKVProperty({ kv.decodeParcelable(it, T::class.java) }, { kv.encode(first, second) })
inline fun <reified T : Parcelable> IMMKVOwner.mmkvParcelable(default: T) =
MMKVProperty({ kv.decodeParcelable(it, T::class.java) ?: default }, { kv.encode(first, second) })
fun <V> MMKVProperty<V>.asLiveData() = object : ReadOnlyProperty<IMMKVOwner, MutableLiveData<V>> {
private var cache: MutableLiveData<V>? = null
override fun getValue(thisRef: IMMKVOwner, property: KProperty<*>): MutableLiveData<V> =
cache ?: object : MutableLiveData<V>() {
override fun getValue() = this@asLiveData.getValue(thisRef, property)
override fun setValue(value: V) {
if (super.getValue() == value) return
this@asLiveData.setValue(thisRef, property, value)
super.setValue(value)
}
override fun onActive() = super.setValue(value)
}.also { cache = it }
}
fun <V> MMKVProperty<V>.asFlow() = object : ReadOnlyProperty<IMMKVOwner, MutableSharedFlow<V>> {
private val cache = MutableSharedFlow<V>()
override fun getValue(thisRef: IMMKVOwner, property: KProperty<*>): MutableSharedFlow<V> {
return cache
}
}
class MMKVProperty<V>(
private val decode: (String) -> V,
private val encode: Pair<String, V>.() -> Boolean,
var key: String? = null
) : ReadWriteProperty<IMMKVOwner, V> {
override fun getValue(thisRef: IMMKVOwner, property: KProperty<*>): V =
decode(key ?: property.name)
override fun setValue(thisRef: IMMKVOwner, property: KProperty<*>, value: V) {
encode((key ?: property.name) to value)
}
}
优雅使用
object Account : MMKVOwner(mmapID = "account") {
//default后可传默认值
var accountName by mmkvString(default = "")
var accountId by mmkvInt(default = -1)
var userId by mmkvLong(default = -1)
var isShow by mmkvBool(false)
var topMenu: List<String> by mmkvList(default = emptyList())
var appServerConfig: AppConfigModel by mmkvJsonObject(
AppConfigModel(
resumeAdTime = 60,
cloudCZUrl = "",
cardCZUrl = "",
cloudTipsTitle = "",
topMenu = emptyList(),
bottomMenu = emptyList()
)
)
}
//赋值
Account.accountName = "aaaaa"
//取值
val name = Account.accountName