SharedPreferences
SharedPreferences这个api用的还是蛮多的,像存储一些简单的东西就很爽。 但是有很多博客都在讨论,SharedPreferences 不能存太多的东西,它会把数据缓存到内存中。数据量太多会影响存储效率,应该分很多个文件存储等等,下面我们就从一些角度上尝试解读下这些问题,
存储位置
这个存储位置还是比较重要的,在查阅谷歌Android 文档 的时候发现,他是通过xml 存储在/data/data//shared_prefs目录下。比如像这样
通过上面的图片大体可以知道这个xml的名字和存储方式。
挖坑
- 这个xml是否可以存储到其他位置?
- 它存到应用所占用的空间中是否会影响app启动和运行效率?
- 分为多个xmL时,和使用一个xml文件读写效率是否一致?
- 是否可以通过绑定生命周期的方式动态的从内存中移出加载?
使用方式:初始化
SharedPreferences 是interface,反正我是没有看到implements SharedPreferences 这种写法的。
这就涉及到context的子类 ContextImpl,
ContextImpl是
Context API的通用实现,它为Activity和其他应用程序组件提供了基础上下文对象
通过ContextImpl 获取到的SharedPreferences 其实是SharedPreferencesImpl类,这个类实现了SharedPreferences。
生成对象的时候会mod传入 xml对应的file文件和mode值,通过 loadFromDisk 将xml file 中的值存储到一个 Map<String, Object> mMap 中。
emmm? 这个地方不是new 了一个线程吗?为啥有大佬说这个SharedPreferences 初始化不建议放到进程启动的时候 ,先挖一个坑,
-
这个地方就可以解释是否可以将SharedPreferences对应的xml 放置到其他地方了,不行的,ContextImpl的实现决定了这个问题,当然复制一套代码读取外部的xml应该是没有问题的。
所以初始化:**Context.getSharedPreferences("xml的名字",mode)。**
mode来源于Context。
Context.MODE_PRIVATE(只能被自己的应用程序访问)
Context.MODE_WORLD_READABLE(除了自己访问外还可以被其它应该程序读取)
Context.MODE_WORLD_WRITEABLE(除了自己访问外还可以被其它应该程序读取和写
Context.MODE_WORLD_WRITEABLE(除了自己访问外还可以被其它应该程序读取和写入)
后面的这几个没有用过,也不好说
Context.MODE_APPEND(文件创建模式:与{@link #openFileOutput}一起使用,如果文件*已经存在,则将数据写入现有文件的末尾*而不是擦除它。)
Context.MODE_MULTI_PROCESS(SharedPreference loading flag: when set, the file on disk will be checked for modification even if the shared preferences instance is already loaded in this process. This behavior is sometimes desired in cases where the application has multiple processes, all writing to the same SharedPreferences file. Generally there are better forms of communication between processes, though.)
通常来讲,Context.MODE_PRIVATE是用的最多的一个值。
存储和更新
SharedPreferences 可以存储的基础数据类型:布尔型、浮点型、整型、长整型和字符串型
写入需要获取 Editor 对象。既然 SharedPreferencesImpl实现了SharedPreferences,那么 Editor的实现类就是EditorImpl了。
通过截图我们可以看到,当我们put的时候,仅仅是放到了一个map 里面,而且在通过SharedPreferences获取到Editor 对象的时候他是这么写的
啊哈,曾经的疑惑终于解开了,为啥我上一行存储的到Editor中的值在第2行获取到的Editor 中为啥没有,还有为啥我们没有执行保存操作 apply()和commit() 数据就消失了。
所以就有必要解释下上面这两个方法了。
apply()和commit()都是将输入写入到xml文件中的意思
这很明显可以看到这个方法是异步的。
而commit()却是同步带返回值的。
在方法commitToMemory()中我们可以找到已有map和新map数据对比的部分。
mapToWriteToDisk 是指 SharedPreferences获取的所有数据。
mModified是指当前EditorImpl对象中存储的数据。
上面这个图的代码逻辑也解释了数据的存储和替换删除逻辑。所以存储也大致是这些了。
获取
从SharedPreferences获取值就简单了,直接通过get***获取就好了,因为在创建SharedPreferences对象的时候会把所有数据从xml中读取到map 中,所以本质上就是通过key在map 中获取值。
synchronized 加锁
在SharedPreferencesImpl文件中包含了大量的synchronized相关代码。 在并发编程中存在线程安全问题,主要原因有:1.存在共享数据 2.多线程共同操作共享数据。关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchronized可以保证一个线程的变化可见(可见性),即可以代替volatile。
最后一个问题
我在用SharedPreferences的时候,所以的博客都在告诉我,要分xml,不用的功能模块尽量存放不同下xml文件。那么我猜可能有以下原因:
-
虽然在创建SharedPreferences对象的时候有开启线程读取对应xml文件中的数据转map,但是因为加锁机制导致需要等数据获取成功后才能读取数据,而get***的时候一般在主线程。
-
存储问题,因为存储特性。他好像是把map 全部存储进去的(***挖一个坑,需要了解下XmlUtils ***)而通过commit()同步返回,大数据量可能会比较慢
-
map本身的原因(留一个坑因为要下班了,哈哈哈哈,嗝)
我思想可能出了问题,留了坑还要发博客。
ps