Android-带你从源码角度理解SharedPreferences存储原理

SP的特点以及基本使用方式

SharedPreferences因非常适合存储较小键值集合数据且使用非常简单的特点,而受到广大程序员们热爱。
SP使用非常简单:


//读操作
Context context = getActivity();
SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE);
String result = sp.getString("key", "defaultValue");

//写操作
Context context = getActivity();
SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE);
sp.edit().putString("key", "value").commit();

SP源码分析

SP是如何读取数据的

其实Context实现就是ContextImpl中,要想搞清楚SP是如何读取数据的,第一步当然是要了解ContextImpl.getSharedPreferences方法是如何实现的


    /**
     * Map from package name, to preference name, to cached preferences.
     */
     //缓存所有应用的SP容器,该容器key对应应用名称,value则为每个应用存储所有sp的容器(ArrayMap)
    private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;

   @Override
    public SharedPreferences getSharedPreferences(String name, int mode) {
        SharedPreferencesImpl sp;
        synchronized (ContextImpl.class) {
            if (sSharedPrefs == null) {
                //如果静态对象不存在,直接创建一个Map,以便后期用于保存sp
                sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();
            }

            //获取当前应用包名
            final String packageName = getPackageName();

            //从保存sp的容器中通过包名查找当前应用所有sp;每个app的所有sp都是保存在ArrayMap中,
            ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);

            if (packagePrefs == null) {

                //如果从sp容器没找到保存当前应用sp的ArrayMap直接创建一个
                packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();

                //将创建的对象保存到sp容器中
                sSharedPrefs.put(packageName, packagePrefs);
            }

            // At least one application in the world actually passes in a null
            // name.  This happened to work because when we generated the file name
            // we would stringify it to "null.xml".  Nice.
            if (mPackageInfo.getApplicationInfo().targetSdkVersion <
                    Build.VERSION_CODES.KITKAT) {
                //如果targetSdk版本好小于19,且传入的文件名为null的话,默认将文件名命名为"null"
                if (name == null) {
                    name = "null";
                }
            }

            //从当前应用的sp容器中通过文件名去查找sp
            sp = packagePrefs.get(name);
            if (sp == null) {

                //如果没找到,直接创建一个文件名以name命名的xml文件
                File prefsFile = getSharedPrefsFile(name);

                //此处极为关键,该构造器是读取文件操作
                sp = new SharedPreferencesImpl(prefsFile, mode);

                //将创建sp对象保存到当前应用sp容器中
                packagePrefs.put(name, sp);
                return sp;
            }
        }
        if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
            getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
            // If somebody else (some other process) changed the prefs
            // file behind our back, we reload it.  This has been the
            // historical (if undocumented) behavior.

            //如果读取模式是跨线程或targetSdk版本小于11,再次重新load下文件而已
            sp.startReloadIfChangedUnexpectedly();
        }
        return sp;
    }

从上面源码可以看出,getSharedPreferences方法是先根据当前应用名称来获取一个ArrayMap(存储sp的容器)如果没有直接创建并保存到内存中,然后再根据文件名来获取SharedPreferencesImpl的对象(没找到则直接创建SharedPreferencesImpl),这短短的三十几行代码还是比较简单的。
因为是静态变量存储键值数据的所以我们用SP存储的数据在内存中是一直存在;所以我们尽量用一个文件来存在数据,以达到减少内存对象

大家可以看到getSharePreferences返回的对象类型其实是SharedPreferencesImpl类型,只不过该类实现了SharedPreferences接口而已,接下来我们先看看SharedPreferencesImpl构造器做了啥东东。

SharedPreferencesImpl.java

    final class SharedPreferencesImpl implements SharedPreferences {

        private final File mFile;
        private final File mBackupFile;
        private final int mMode;

        private Map<String, Object> mMap;     // guarded by 'this'
        private int mDiskWritesInFlight = 0;  // guarded by 'this'

        //文件是否加载成功
        private boolean mLoaded = false;      // guarded by 'this'

        //文件的时间以及大小
        private long mStatTimestamp;          // guarded by 'this'
        private long mStatSize;               // guarded by 'this'

        private final Object mWritingToDiskLock = new Object();
        private static final Object mContent = new Object();
        private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
                new WeakHashMap<OnSharedPreferenceChangeListener, Object>();

        SharedPreferencesImpl(File file, int mode) {
            //给类成员变量赋值
            mFile = file;
            mBackupFile = makeBackupFile(file);
            mMode = mode;
            mLoaded = false;
            mMap = null;

            //开启一个线程读取文件
            startLoadFromDisk();
        }

        private static File makeBackupFile(File prefsFile) {
            return 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值