文本

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,就会报错
相关推荐
测开小菜鸟5 分钟前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity1 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天1 小时前
java的threadlocal为何内存泄漏
java
caridle1 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋31 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花2 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端2 小时前
第六章 7.0 LinkList
java·开发语言·网络
Wx-bishekaifayuan2 小时前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava
customer082 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源