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。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章