文本

MMKV、SharedPreference 和 DataStore

2.2 MMKV

为啥有用户层 和 内核层

主要是为了安全,如果没有内核层,一个程序把系统给弄挂了,其他的也都会不能用

2.2.1 首先说一下 SharedPreference 原理

getSharedPreferences的时候其实就是先从缓存中拿 这个xml的File,如果缓存没有,直接去new一个File,并且读取。然后通过传统的I/O 去读取xml,利用xml解析器解析这个xml,存到Map中

  • 读数据:读取的时候从map中读的,
  • 写数据:commit 是同步的写入,先写入内存,然后全量写入到xml中 ,apply 是异步的写入xml,通过一个QueuedWork写的
  • 不丢全量数据(说的是全量数据,只会丢一次的数据,比如写的时候,啥进程。)

他的缺点有很多

  1. FileoutStream ,读取xml传统I/O,比如写,先从用户内存,写到内核空间,然后再写到为文件中,相当于两次copy,SP第一次加载数据时需要全量加载,当数据量大时可能会阻塞UI线程造成卡顿
  2. 序列化 用的xml,使用DOM解析,
  3. 不能差量更新,只能更新全部的xml内容
  4. 拿不到返回结果,虽然commit可以,但是commit会阻塞线程,apply 拿不到
  5. 虽然apply 是开辟了线程,但是没有返回值
  6. sp不能跨进程,我记得7.0以前是可以的,7.0之后mode必须是priate了
  7. 容易造成ANR字节的公众号,commit 需要等 xml读入完毕, apply的问题,apply 会放入一个QueuedWork里面取执行,开始执行会加锁,执行完毕会释放锁,但是Activity onStop 以及 Service 处理 onStop,onStartCommand 时,执行 QueuedWork.waitToFinish() 等待所有的等待锁释放,头条的做法是,hook系统ActivityThread的H的Handler,在这个Handler里面加了个 CallBcak ,Handler 的 dispatchMessage 中会先处理 callback,可以在这里监听Activity的onStop的时候清除这个QueuedWork
java 复制代码
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
    File file;
    synchronized (ContextImpl.class) {
        if (mSharedPrefsPaths == null) {
            mSharedPrefsPaths = new ArrayMap<>();
        }
        file = mSharedPrefsPaths.get(name);
        if (file == null) {
            file = getSharedPreferencesPath(name);
            mSharedPrefsPaths.put(name, file);
        }
    }
    return getSharedPreferences(file, mode);
}

2.2.2 MMKV(Memory Mapping Key Value)优点

  • mmap,是Linux 为咱们提供的方式,同时还有sendFile,数据拷贝相当于拷贝了一次,当写的时候,从用户空间到内核空间,然而内核空间利用mmap映射到文件,相当于直接操作文件的,相当于直接写内存,MMAP使用逻辑内存对磁盘文件进行映射,App只管往里面写数据,由操作系统负责将内存,不必担心crash 导致数据丢失
  • 不需要开辟线程,操作内存就相当于操作文件,不需要开启线程,操作MMAP的速度和操作内存的速度一样快
  • 效率更高。MMKV 使用protobuf进行序列化和反序列化,是二进制数据,不容易阅读,protobuf是可变编码(和H264的哥伦布差不多),其他的是定长编码,定长编码:比如 int 占 4个字节,你是1也占4个字节,但是protobuf 只是占用1位就可以了,一个字节8位,他是通过 一些简单的 & 做到的。然后做移动。
  • 可以支持增量更新,只是在protobuf追加在数据的最后面,当数量达到申请的大小时候,开始去除重复的key,扩容的时候,也是double现在的size 跟 Hashmap一样,会重新计算,看是否能撑得下,然后再固定大小,也是很耗时的。
  • 多进程

2.2.3 mmmap 缺点

  • 因为 MMap 需要提供一度长度的内存块,其映射区的长度默认是一页,即 4kb,当存储的文件内容较少时可能会造成空间的浪费
  • 没有提供注册value变化监听的,(自己封装的时候,做了一层)
  • 增量更新,并没有判断value 是否相同就直接追加(自己封装的时候,做了一层)23-11-20号已经修改,因为扩容的原因,所以网上写的存大字符串会比其他的慢的原因
  • clearAll的时候,会恢复到4k,(23-11-20号,保持文件磁盘空间不变)
  • 没有像Hashmap一样可以初始化大小,默认就是4kb(23-11-20号已经增加)
  • 丢数组,断电关机------磁盘里的文件就会以这种写了一半的、不完整的形式被保留,此时就会损坏(自己做了恢复。已启动的时候,同时存入DataStore中一个数据,如果拿到不一样,就证明丢失了,此时同步数据)

2.3 google新出来的 DataStore

DataStore 是 Android Jetpack 的一部分。Jetpack DataStore 是一种数据存储解决方案,允许您使用协议缓冲区存储键值对或类型化对象,官方建议如果当前在使用 SharedPreferences 存储数据,请考虑迁移到 DataStore

  • Preferences DataStore 以键值对的形式存储在本地和 SharedPreferences 类似,此实现不需要预定义的架构,也不确保类型安全。Preferences DataStore 只支持 Int , Long , Boolean , Float , String 键值对数据,适合存储简单、小型的数据,并且不支持局部更新,如果修改了其中一个值,整个文件内容将会被重新序列化。
  • Proto DataStore 将数据作为自定义数据类型的实例进行存储。此实现要求您使用协议缓冲区来定义架构,但可以确保类型安全。Proto DataStore 使用了二进制编码压缩,体积更小,速度比 XML 更快

主要优点

  1. 内部使用kotlin协程,避免阻塞线程
  2. 可以使用 protoccol buffers 存储,更小
  3. 可以在编译期间提醒类型错误,sp 直接getInt ,如果里面是String,就会报错
相关推荐
战族狼魂3 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
xyliiiiiL4 小时前
ZGC初步了解
java·jvm·算法
杉之4 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
hycccccch5 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
天天向上杰6 小时前
面基JavaEE银行金融业务逻辑层处理金融数据类型BigDecimal
java·bigdecimal
请来次降维打击!!!6 小时前
优选算法系列(5.位运算)
java·前端·c++·算法
用键盘当武器的秋刀鱼6 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端
嘤国大力士7 小时前
C++11&QT复习 (七)
java·c++·qt
松树戈7 小时前
Java常用异步方式总结
java·开发语言
weisian1517 小时前
Java常用工具算法-3--加密算法2--非对称加密算法(RSA常用,ECC,DSA)
java·开发语言·算法