作为一个Android小菜,一直觉得写博客分享是一件高大上的事情,今天本菜也要做一下高大上的事情,好了,废话不多说,Talk is cheap. Show me the code!
最近在考虑在应用程序中怎样优雅的保存全局变量,现在大致有三种方法,一种是通过自己继承Application,在application中保存;一种是写一个专门保存变量的类;另外一种是通过SP存储实现;但是SP存储是存储到磁盘上,定会影响效率,但是SP存储的读取是如何操作呢?这就引起了本菜的好奇,去探究了一番。
众所周知,我们获得sharePreference
实例是通过getSharedPreferences
函数获取,在Activity中调用该函数实则调用了ContextWrapper中的getSharedPreferences
函数,ContextWrapper的getSharedPreferences
重写了Context中的getSharedPreferences
,但是这里getSharedPreferences
是一个抽象函数,容本菜道行不够,找不到getSharedPreferences
的具体实现;
话锋一转,我们来看看SharedPreferences
类,
* @see Context#getSharedPreferences
*/
public interface SharedPreferences {
这里可知SharePreference是一个接口,既然是接口,就有实现:
final class SharedPreferencesImpl implements SharedPreferences {
前人的肩膀就是高,我们找到了实现。首先我们探究下存储操作,这里我们以存储字符串为例:
boolean isSucessful = getSharedPreferences("config",Context.MODE_PRIVATE)
.edit()
.putString("妹纸漂亮","妹纸是漂亮")
.commit();
SharedPreferences.Editor是用来进行存储操作的,它做了什么呢,查看实现:
public final class EditorImpl implements Editor {
private final Map<String, Object> mModified = Maps.newHashMap();
private boolean mClear = false;
public Editor putString(String key, @Nullable String value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
public Editor putStringSet(String key, @Nullable Set<String> values) {
synchronized (this) {
mModified.put(key,
(values == null) ? null : new HashSet<String>(values));
return this;
}
}
public Editor putInt(String key, int value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
首先Editor声明一个HashMap,看到这里我们懂了,我们所做的存储操作首先是先存储到HashMap中,那什么时候会存储到磁盘上呢,当然是我们调用comit()或者apply()之后啊!我们来看官方关于这两个函数的描述:
通过对比我们知道:
- apply()没有返回值,而commit()是有返回值的,返回值标识着是否执行成功。
- apply()的操作是原子提交到内存中,然后以异步的方式保存到磁盘上,而commit()完全是以同步的方式将数据保存到磁盘上。
- apply()因为没有返回值,所以不会提示任何失败。只需要调用即可。
- 无论是apply()还是commit(),如果同时被操作了,以最后一次操作为准。
之后我们再看读取的操作:
public String getString(String key, @Nullable String defValue) {
synchronized (this) {
awaitLoadedLocked();
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
这里我们看到,我们获取值是从Map集合中获取,那么Map集合什么时候获取的值呢?
private void loadFromDisk() {
.....
Map map = null;
....
map = XmlUtils.readMapXml(str);
....
mMap = map;
.....
}
原来是从loadFromDisk函数中获取的啊,那么这个函数是什么时候调用的呢?
SharedPreferencesImpl(File file, int mode) {
....
startLoadFromDisk();
}
private void startLoadFromDisk() {
.....
new Thread("SharedPreferencesImpl-load") {
public void run() {
loadFromDisk();
}
}.start();
}
在构造函数中就调用了该函数,而且该函数是异步加载;由此我们可知,在使用sp读取数据的时候,会将文件中的所有数据都加载到内存中。所以我们在使用sp的时候,为了节约内存,可以多存几个sp文件,这样我们通过sp读取数据的时候,不会因为数据太多,导致内存使用急剧上升。
本菜水平有限,如果文章内容使您感到不适,请通知我,我会改正到您更加的不适。
感谢承香墨影大大的文章;大家有兴趣可以去看看,传送门在下方:
链接:http://www.jianshu.com/p/4c4bd044909f