MMKV、DataStore、SharedPreferences 到底怎么选?

3,192 阅读5分钟

前言

image.png MMKV、DataStore、SharedPreferences 键值对存储方案到底该怎么选?

看完此篇文章或许就会有了答案!

SharedPreferences

一、简介

SharedPreference(简称SP) 是一个轻量级的数据存储方式,使用方便,以键值对的形式存储在本地。

二、优点

1、使用简单,不丢数据

使用非常方便,能确保数据的一致性,适合不频繁读写一些重要的数据

三、缺点

1、SP 不能保证类型安全

获取数据的时候可能出现 ClassCastException 异常,因为使用相同的KEY调用 put() 保存不同类型的数据时会覆盖掉之前保存的数据类型。

2、SP 加载的数据会一直留在内存中

使用getSharedPreferences() 方法加载数据会将数据存储在静态的成员变量中,然后通过静态的 ArrayMap 缓存每一个 SP 文件,而每个 SP 文件内容通过 Map 缓存键值对数据,这样数据会一直留在内存中,浪费内存。

3、不支持多进程

SP不支持夸进程跨进程通信;代码里可以看到当使用多进程 MODE_MULTI_PROCESS 操作的时候,会重新读取 SP 文件内容。

image.png

4、读写性能差,可能引起ANR

读取数据时候虽然加载文件也是异步加载的,不过sp.get()方法是同步的,如果代码在它加载完成之前就去尝试读取键值对,线程就会阻塞,直到文件加载完成,此时如果在主线程操作的话,就会造成界面卡顿.

写入数据时SP可以通过apply()异步的方式来保存更改来避免 I/O 操作所导致的主线程的耗时,但当 Activity 启动和关闭的时候会等待这些异步提交完成保存之后,这就相当于把异步操作转换成同步操作了,从而会导致卡顿甚至 ANR。 当然这些操作也是为了能保证数据安全一致而为之。

具体ANR引起原因可以参考:字节跳动剖析 SharedPreference apply 引起的 ANR 问题

DataStore

一、简介

Jetpack DataStore 是一种数据存储解决方案,允许您使用协议缓冲区存储键值对或类型化对象。DataStore 使用 Kotlin 协程和 Flow 以异步、一致的事务方式存储数据。(来自官方介绍) image.png

二、优点

1、性能高,不卡顿,不丢数据

DataStroe基于Kotlin协程实现和使用,官方主推性能,主线程读写(不管大小)数据都不卡顿(MMKV读写长字符串时可能会发生卡顿)

2、官方站台主推数据存储方案

官方替代SharedPreference方案,SP有的基础上并优化了性能问题,选择存储方案时应该优先考虑,官方出品必属精品?

三、缺点

1、不支持多进程

暂时不支持多进程;不过从 DataStore 提交的代码来看,它已经在加入多进程的支持了,但目前还没有实现。

2、需要支持KT协程

DataStroe基于Kotlin协程实现和使用,如果你的项目还是纯Java的话,还是用SP忍一忍吧。

MMKV的区别

一、简介

MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。从 2015 年中至今在微信上使用,其性能和稳定性经过了时间的验证。近期也已移植到 Android / macOS / Win32 / POSIX 平台,一并开源。

image.png

点我查看官方介绍

二、优点:

1、支持多进程

如果你的公司需要支持多进程通信,你就暂时只能使用MMKV了

2、快快快

单进程性能

MMKV & SharedPreferences & SQLite 读写速度对比: image.png 无MMKV 在写入性能上远远超越 SharedPreferences & SQLite,在读取性能上也有相近或超越的表现。

多进程性能

MMKV & SharedPreferences & SQLite 读写速度对比: image.png 可见,MMKV 无论是在写入性能还是在读取性能,都远远超越 MultiProcessSharedPreferences & SQLite & SQLite, MMKV 在 Android 多进程 key-value 存储组件上是不二之选

MMKV特别适合高频的读写数据 比如微信聊天记录即时保存显示场景可以参考:抛物线大佬的文章

三、缺点

1、写入大数据速度较慢

当使用MMKV写入大的字符串数据时,相比于SP和DataStore会慢些,但是开发中基本不会写入那么大的字符串的吧。

2、可能会丢数据

当设备突然断电关机等意外现象时,刚好数据保存在一半的情况下,此时文件就会发生损坏。这种问题是不可能避免的,MMKV 的底层机制在断电关机之类的操作系统级别的崩溃,没有做备份还原的操作,数据就会损失重置;MMKV 底层的原理是内存映射,它不是实时的将内存中的数据写入到往磁盘里中的,会有一些滞后性,MMKV定位于高频写入可能这就是它不实时写入磁盘的原因吧;

而SharedPreferences 和 DataStore 的应对方式是在每次写入新数据之前都对现有文件做一次自动备份,这样在发生了意外出现了文件损坏之后,它们就会把备份的数据恢复过来。

总结

1、如果你的应用支持KT协程,并且不需要多进程去存储数据,也没有高频同步写入数据场景,无疑谷歌的亲儿子DataStore是你优化考虑的对象。

2、需要多进程存储数据、并且可能会有高频同步写入数据、可以忽略那特殊情况下的数据丢失MMKV是你的不二之选。

3、至于SP的话,老派JAVA项目,没有高频同步写入数据,需要保证数据绝不丢失,忍着用吧。