锦囊篇|一文摸懂 SharedPreferences 和 MMKV(一)
使用方法
SharedPreferences
MMKV
第一步:开源库导入
第二步:使用
为什么这篇文章要拿两个框架讲?
单进程性能
多进程性能
不论是单线程还是多线程,MMKV
的读写能力都远远的甩开了SharedPreferences
&SQLite
&SQLite+Transacion
。不过下面一句话仅代表了我的个人意见,也是为什么我只写SharedPreferences
和MMKV
两者比较的原因,因为我个人认为SQLite
和他们不太属于同一类产品,所以比较的意义上来说就趋于普通。
SharedPreferences源码分析
根据上述中所提及过的使用代码,能够比较清楚的知道第一步的分析对象就是getSharedPreferences()
的获取操作了,但是如果你直接点进去搜这个方法,是不是会出现这样的结果呢?
没错了,只是一个抽象方法,那显然现在最重要的事情就是找到他的具体实现类是什么了,当然你可以直接查阅资料获取,最后的正确答案就是ContextImpl
,不知道你有没有找对呢?
在上面的使用过程中提到了,其他他是一个副本的概念,这个从何说起呢?显然这就要看一下SharedPreferences
的实现类具体是如何进行操作的了,从他的构造函数看起,慢慢进入深度调用。
到此为止就基本完成了SharedPreferences
的构建流程,而为了能够对数据进行操作,那就需要去获取一只笔,来进行操作,同样的这段代码最后会在SharedPreferencesImpl
中进行具体实现。
因为后面的操作都是与这只笔相关,而且具体操作上重复度比较高,所以只选取一个putString()
来进行分析。
很简单的解决思路,就是新创建一个了HashMap
里面全部保存的都是一些我们已经做过修改的数据,之后的更新是需要用到这些数据的。
相较于之前的那些源码,这里的就显得非常轻松了,结合上述的源码分析,可以假设SharedPreferences
氛围三个要点。
mMap: 存储从文件中拉取的数据。
mModified: 存储希望修改值的数据。
apply()/commit(): 猜测最后就是上述两者数据的合并,再进行数据提交。
数据提交
异步提交 / apply()
从上述的代码中可以了解到apply()
的通过创建一个线程来进行处理,之后会讲到commit()
和他的处理方式不同的地方。现在具体的目光还是要聚焦在如何完成数据到磁盘的提交的,也就是注释1处的具体实现到底是如何?这就是对这个类的一个理解问题了。其实他有点类似于程序计数器,在阻塞数量大于线程数时,会阻塞运行,而超出数量就会出现并发状况。
第二个地方就是注释2,他线程做了一个入队列的操作。
同步提交 / commit()
所以说基本逻辑上其实还是和apply()
方法是一致的,只是去除了异步处理的步骤,所以就是常说的同步处理方式。
总结
**是什么限制了
SharedPreferences
的处理速度?**
这个问题在上面的源码分析中其实已经有所提及了,那就是文件读写,所以如何加快文件的读写速度是一个至关重要的突破点。当然向速度妥协的一个方案,想来你也已经看到了,那就是异步提交,通过子线程的在用户无感知的情况下把数据写到文件中。
为什么多线程安全,而多进程不安全的操作?
多线程安全安全想来是一个非常容易解释的事情了,干一个很简单的事情就是synchronized
的加锁操作,对数据的操作进行加锁那势必拿到的最后数据就会是一个安全的数据了。
但是对于多进程呢? 你可能会说在sp.startReloadIfChangedUnexpectedly();
这段代码出现的难道不是已经涉及了多进程的安全操作吗?yep!! 如果你想到了这点,说明你有好好看了下代码,但是没有看他的实现,如果你去看他的实现方案,就会发现MODE_MULTI_PROCESS
和所可以使用的操作的运算结果均为0
,所以在现在的Android
版本中这是一个被抛弃的方案。当然这是其一,自然还有另外一个判断就是关于版本方面,如果小于HONEYCOMB
同样可以进入这个方案,但是需要注意getSharedPreferences()
是只有获取时才会出现的,而SharedPreferences
是对于单进程而言的单独实例,数据的备份全部在单个进程完成,所以在进行多进程读写时,发生错误是大概率的。
版权声明: 本文为 InfoQ 作者【ClericYi】的原创文章。
原文链接:【http://xie.infoq.cn/article/9ce1a6d75ca058dcb4547e683】。文章转载请联系作者。
评论