全面剖析SharedPreferences

1.原理和概述

  • 1.儲存于硬盤上的xml鍵值對。
  • 2.輕量級數(shù)據(jù)儲存,數(shù)據(jù)多了容易引起性能問題
  • 3.xml文件所在目錄位于/data/data//shared_prefs/,可以有多個文件。

2.初始化

  1. ContextImpl記錄著SharedPreferences的重要數(shù)據(jù)
    1.sSharedPrefsCache:以包名為key, 二級key是以SP文件, 以SharedPreferencesImpl為value的嵌套map結(jié)構(gòu). 這里需要sSharedPrefsCache是靜態(tài)類成員變量, 每個進程是保存唯一一份, 且由ContextImpl.class鎖保護.
    2.mSharedPrefsPaths:記錄所有的SP文件, 以文件名為key, 具體文件為value的map結(jié)構(gòu)
    3.mPreferencesDir:是指SP所在目錄, 是指/data/data//shared_prefs/

  2. Context.getSharedPreferences(name, mode)獲取SharedPreferences,只要是Context都能獲取
    1.先從mSharedPrefsPaths查詢是否存在相應文
    2.如果文件不存在, 則創(chuàng)建新的xml文件; 如果目錄也不存在, 則先創(chuàng)建目錄創(chuàng)建目錄/data/data/package name/shared_prefs/

  3. 檢查mode
    。1.MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE 在android N開始就會拋出異常,防止外部應用讀寫該文件
    。2.MODE_MULTI_PROCESS 是多進程方式使用文件,由于有內(nèi)存緩存的緣故這種模式下不怎么能保證進程安全,后續(xù)google不再支持。代替的方式有ContentProvider。

  4. 創(chuàng)建同名的.bak備份文件用于發(fā)生異常時, 可通過備份文件來恢復數(shù)據(jù).

  5. 將xml文件加載到內(nèi)存中,這個操作的線程是新開的,但是會阻塞getXXX()和setxxx()以及edit()方法。

  6. 一旦完全加載到內(nèi)存, 后續(xù)的getXXX()則是直接訪問內(nèi)存

3.讀取

  1. 在xml文件全部內(nèi)加載到內(nèi)存中之前,讀取操作是阻塞的
  2. 在xml文件全部內(nèi)加載到內(nèi)存中之后,是直接讀取內(nèi)存中的數(shù)據(jù)

4.寫入

    1. 獲取一個Editor
    1. putXXX的時候,只是將數(shù)據(jù)寫入到內(nèi)存中的一個mModified Map中
    1. 執(zhí)行commit 或 apply操作
      。 1.commit:

      • 1.將mModified的數(shù)據(jù)更新到SPI的mMap中
      • 2.當沒有key發(fā)生改變, 則直接返回; 否則將mMap全部信息寫入文件, 如果寫入成功則刪除備份文件,如果寫入失敗則刪除mFile
      • 3.每次commit是把全部數(shù)據(jù)更新到文件, 所以每個文件的數(shù)據(jù)量必須保證足夠精簡

      。 2.apply:

      • 1.apply跟commit的最大區(qū)別 在于apply的寫入文件操作是在單線程的線程池來完成.而commit是在當前線程阻塞運行的。
      • 2.apply方法開始的時候, 會把一個任務(wù)awaitCommit,放入一個任務(wù)隊列中QueuedWork
      • 3.單線程池會不斷從QueuedWork取任務(wù)然后執(zhí)行。
      • QueuedWork在這里存在的價值主要是用于在Stop Service, finish BroadcastReceiver過程用于 判定是否處理完所有的異步SP操作.
    1. 總結(jié)
      1.apply因為是異步的沒有返回值, commit是同步的有返回值能知道修改是否提交成功
      2.多并發(fā)的提交commit時,需等待正在處理的commit數(shù)據(jù)更新到磁盤文件后才會繼續(xù)往下執(zhí)行,從而降低效率; 而apply只是原子更新到內(nèi)存,后調(diào)用apply函數(shù)會直接覆蓋前面內(nèi)存數(shù)據(jù),從一定程度上提高很多效率。
      3.edit()每次都是創(chuàng)建新的EditorImpl對象.

5.優(yōu)化

  1. sp里面存儲特別大的key/value, 有助于減少卡頓/anr
  2. 不要高頻地使用apply和commit, 盡可能地批量提交。因為每次提交就是xml文件的全部重寫
  3. commit直接在主線程操作, 要注意
  4. 不要使用MODE_MULTI_PROCESS,多線程不應該使用SPI
  5. 高頻寫操作的key與高頻讀操作的key可以適當?shù)夭鸱治募? 由于減少同步鎖競爭
  6. 不要一上來就執(zhí)行g(shù)etSharedPreferences().edit(),因為getSharedPreferences()是在其他線程進行但是會阻塞.edit()。
  7. 不要連續(xù)多次edit(), 應該獲取一次獲取edit(),然后多次執(zhí)行putxxx(), 減少內(nèi)存波動。

參考文章:全面剖析SharedPreferences

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容