全面剖析SharedPreferences

1.原理和概述

  • 1.儲存於硬盤上的xml鍵值對。
  • 2.輕量級數據儲存,數據多了容易引發性能問題
  • 3.xml文件所在目錄位於/data/data//shared_prefs/,能夠有多個文件。

2.初始化

  • 1.ContextImpl記錄着SharedPreferences的重要數據
    • 1.sSharedPrefsCache:以包名爲key, 二級key是以SP文件, 以SharedPreferencesImpl爲value的嵌套map結構. 這裏須要sSharedPrefsCache是靜態類成員變量, 每一個進程是保存惟一一份, 且由ContextImpl.class鎖保護.
    • 2.mSharedPrefsPaths:記錄全部的SP文件, 以文件名爲key, 具體文件爲value的map結構
    • 3.mPreferencesDir:是指SP所在目錄, 是指/data/data//shared_prefs/
  • 2.Context.getSharedPreferences(name, mode)獲取SharedPreferences,只要是Context都能獲取
    • 1.先從mSharedPrefsPaths查詢是否存在相應文
    • 2.若是文件不存在, 則建立新的xml文件; 若是目錄也不存在, 則先建立目錄建立目錄/data/data/package name/shared_prefs/
    • 3.檢查mode
      • 1.MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE 在android N開始就會拋出異常,防止外部應用讀寫該文件
      • 2.MODE_MULTI_PROCESS 是多進程方式使用文件,因爲有內存緩存的緣故這種模式下不怎麼能保證進程安全,後續google再也不支持。代替的方式有ContentProvider。
    • 4.建立同名的.bak備份文件用於發生異常時, 可經過備份文件來恢復數據.
    • 5.將xml文件加載到內存中,這個操做的線程是新開的,可是會阻塞getXXX()和setxxx()以及edit()方法。
    • 6.一旦徹底加載到內存, 後續的getXXX()則是直接訪問內存

3.讀取

  • 1.在xml文件所有內加載到內存中以前,讀取操做是阻塞的
  • 2.在xml文件所有內加載到內存中以後,是直接讀取內存中的數據

4.寫入

  • 1.獲取一個Editor
  • 2.putXXX的時候,只是將數據寫入到內存中的一個mModified Map中
  • 3.執行commit 或 apply操做
    • 1.commit:
      • 1.將mModified的數據更新到SPI的mMap中
      • 2.當沒有key發生改變, 則直接返回; 不然將mMap所有信息寫入文件, 若是寫入成功則刪除備份文件,若是寫入失敗則刪除mFile
      • 3.每次commit是把所有數據更新到文件, 因此每一個文件的數據量必須保證足夠精簡
    • 2.apply:
      • 1.apply跟commit的最大區別 在於apply的寫入文件操做是在單線程的線程池來完成.而commit是在當前線程阻塞運行的。
      • 2.apply方法開始的時候, 會把一個任務awaitCommit,放入一個任務隊列中QueuedWork
      • 3.單線程池會不斷從QueuedWork取任務而後執行。
      • QueuedWork在這裏存在的價值主要是用於在Stop Service, finish BroadcastReceiver過程用於 斷定是否處理完全部的異步SP操做.
  • 4.總結
    • 1.apply由於是異步的沒有返回值, commit是同步的有返回值能知道修改是否提交成功
    • 2.多併發的提交commit時,需等待正在處理的commit數據更新到磁盤文件後纔會繼續往下執行,從而下降效率; 而apply只是原子更新到內存,後調用apply函數會直接覆蓋前面內存數據,從必定程度上提升不少效率。 3.edit()每次都是建立新的EditorImpl對象.

5.優化

  • 1.sp裏面存儲特別大的key/value, 有助於減小卡頓/anr
  • 2.不要高頻地使用apply和commit, 儘量地批量提交。由於每次提交就是xml文件的所有重寫
  • 3.commit直接在主線程操做, 要注意
  • 4.不要使用MODE_MULTI_PROCESS,多線程不該該使用SPI
  • 5.高頻寫操做的key與高頻讀操做的key能夠適當地拆分文件, 因爲減小同步鎖競爭
  • 6.不要一上來就執行getSharedPreferences().edit(),由於getSharedPreferences()是在其餘線程進行可是會阻塞.edit()。
  • 7.不要連續屢次edit(), 應該獲取一次獲取edit(),而後屢次執行putxxx(), 減小內存波動。

參考文章:全面剖析SharedPreferencesandroid

不販賣焦慮,也不標題黨。分享一些這個世界上有意思的事情。題材包括且不限於:科幻、科學、科技、互聯網、程序員、計算機編程。下面是個人微信公衆號:世界上有意思的事,乾貨多多等你來看。 git

世界上有意思的事
相關文章
相關標籤/搜索