sharedPreferences存储实现原理

有几个问题,关于SharedPreference存储

(1)每次调用getSharedPreferences时都会创建一个SharedPreferences对象吗?这个对象具体是哪个类对象?

      答:不是,只要name相同,就会返回同一个,SharedPreferencesImpl对象,packagePrefs存放文件name与SharedPreferencesImpl键值对,sSharedPrefs存放包名与ArrayMap键值对。注意sSharedPrefs是static变量,也就是一个类只有一个实例,因此你每次getSharedPreferences其实拿到的都是同一个SharedPreferences对象。
(2)在UI线程中调用getXXX有可能导致ANR吗?

      答:有可能的,getXXX之前,会给当前线程加锁,如果sp文件特别大,查询非常耗时的时候,有可能ANR
(3)为什么SharedPreferences只适合用来存放少量数据,为什么不能把SharedPreferences对应的xml文件当成普通文件一样存放大量数据?

       答:其实这和第二个问题没有区别,因为SharedPreference是整个文件都加载到内存中,文件太大了会对内存造成压力。
(4)commit和apply有什么区别?
(5)SharedPreferences每次写入时是增量写入吗?

       答:不是,每次都是重新写入,说一下那个mBackupFile,SharedPreferences在写入时会先把之前的xml文件改成名成一个备份文件,然后再将要写入的数据写到一个新的文件中,如果这个过程执行成功的话,就会把备份文件删除。由此可见每次即使只是添加一个键值对,也会重新写入整个文件的数据,这也说明SharedPreferences只适合保存少量数据,文件太大会有性能问题。SharedPreferences每次写入都是整个文件重新写入,不是增量写入。

首先需要明白的一点是sharedPreferences存储的数据是一个xml文件,跟随package联动。

至于它的使用就不用贴代码了,谁都会用,sharedPreferences是一个接口,在Content类中,声明了getSharedPreferences()空实现的一个方法,先看源码

@Override
    public SharedPreferences getSharedPreferences(String name, int mode) {
        SharedPreferencesImpl sp;
        synchronized (ContextImpl.class) {
            if (sSharedPrefs == null) {
                sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();
            }

            final String packageName = getPackageName();
            ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);
            if (packagePrefs == null) {
                packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();
                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) {
                if (name == null) {
                    name = "null";
                }
            }

            sp = packagePrefs.get(name);
            if (sp == null) {
                File prefsFile = getSharedPrefsFile(name);
                sp = new SharedPreferencesImpl(prefsFile, mode);
                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.
            sp.startReloadIfChangedUnexpectedly();
        }
        return sp;
    }

我们可以很明显的看到

  1. 创建ArrayMap集合,集合的key:string,value:ArrayMap<String,SharedPreferenceImpl>
  2. getPackageName(),拿到项目包名;
  3. 根据包名,在第一步创建的ArrayMap集合中找,有没有包名为key的键值对,if逻辑判断
  4. 如果没有,创建一个ArrayMap集合,作为value,包名作为key,存储在第一步创建的集合ArrayMap中
  5. 根据方法传入的SharedPreferences名称,也就是name的String类型参数,在第四步创建的ArrayMap中get查找有没有创建对应名称的SharedPreferenceImpl对象,if逻辑判断
  6. 如果sp为空,创建对应的file文件,将包名称对应的SharedPreferenceImpl对象存储到第四步的ArrayMap中,name作为key
  7. 然后返回第四步以包名称为key的ArrayMap。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章