轻量级存储框架

246 阅读4分钟

一、SharedPreference

1.1、使用

// 初始化一个sp
SharedPreferences sharedPreferences = context.getSharedPreferences("name_sp", MODE_PRIVATE);
// 修改key的值,有两种方法:commit和apply
sharedPreferences.edit().putBoolean("key_test", true).commit();
sharedPreferences.edit().putBoolean("key_test", true).apply();
// 读取一个key
sharedPreferences.getBoolean("key_test", false);

1.2、commit 和 apply 的区别

  • commit:直接在主线程中进行写入操作,属于同步提交,返回boolean值。容易阻塞主线程导致ANR。

  • apply:可能会导致数据丢失,将文件写入操作放到一个Runnable对象中,等待系统在工作线程中调用,属于异步提交,返回void,可能会导致数据丢失。其原理是创建一个等待锁放到QueuedlMork()中,并将真正数据持久化封装成一个任务放到异步队列中执行,任务执行结束会释放锁。而Activity onPuase,onStop以及Scrvice处理 onStop,onStartCommand等情况下,就会执行QueuedWork.waitToFinish()等待QueuedlMork()中的所有问题执行完(主线程等待所有任务)。因此apply 调用次数过多也会容易引起ANR问题。

1.3、优缺点

优点:

  • 使用简单;

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

缺点:

  • SP 不能保证类型安全

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

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

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

  • 不支持多进程

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

  • 读写性能差,可能引起ANR

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

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

二、DataStroe

2.1、优缺点

优点:

  • DataStroe基于Kotlin协程实现和使用,官方主推性能,主线程读写(不管大小)数据都不卡顿。

缺点:

  • 不支持多进程

暂时不支持多进程。

  • 需要支持KT协程

DataStroe基于Kotlin协程实现和使用。

三、MMKV

MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。

3.1、优缺点

优点:

  • 支持多进程

  • 速度快

MMKV 无论是在写入性能还是在读取性能,都远远超越 MultiProcessSharedPreferences & SQLite & SQLite, MMKV 在 Android 多进程 key-value 存储组件上是不二之选。

MMKV特别适合高频的读写数据,比如微信聊天记录即时保存显示场景

缺点:

  • 写入大数据速度较慢

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

  • 可能会丢数据

当设备突然断电关机等意外现象时,刚好数据保存在一半的情况下,此时文件就会发生损坏。这种问题是不可能避免的,MMKV 的底层机制在断电关机之类的操作系统级别的崩溃,没有做备份还原的操作,数据就会损失重置。

四、总结

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

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

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