Android sharePreference源码探究

作为一个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()之后啊!我们来看官方关于这两个函数的描述:
这里写图片描述

这里写图片描述

通过对比我们知道:

  1. apply()没有返回值,而commit()是有返回值的,返回值标识着是否执行成功。
  2. apply()的操作是原子提交到内存中,然后以异步的方式保存到磁盘上,而commit()完全是以同步的方式将数据保存到磁盘上。
  3. apply()因为没有返回值,所以不会提示任何失败。只需要调用即可。
  4. 无论是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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值