寫這篇部落格目的在于鞏固自己對SharedPreferences的了解。SharePreferences是Android系統提供的輕量級資料存儲方案,主要基于鍵值對方式儲存資料,真實的資料是儲存在/data/data/packageName/shared_pref/目錄下面的。可以儲存多種資料到該檔案中,以下是一個簡單的Sharepreference檔案。
從檔案中可以看出就是采用簡單xml方式進行儲存的。
這裡借用Gityuan部落格中的類繼承圖

在Sharepreference中,Sharepreference和Editor隻是兩個接口,在這兩個接口中定義了一個普通的鍵值對存儲的資料一些常用的操作。然後具體你想把這鍵值對存哪,你可以自己定義相應的檔案或資料庫,甚至你可以寫個儲存到網絡中去。在Android系統中給出的是采用xml方式存在xml的檔案中,具體實作類是SharepreferenceImpl和SharepreferenceImpl.EditorImpl。同時在ContextImpl中有Sharepreference的對應記憶體中的資料。
Activity.java
Context采用的是裝飾模式,其中正在幹活的是ContextImpl,mBase即為ContextImpl,具體代碼如下:
ContextImpl.java
正在儲存的檔案擷取是getSharedPrefsFile(name),代碼如下:
在ContextImpl中存在一個靜态的sSharedPrefs,通過它來擷取對應應用的prefs,在通過prefs找到對應名稱的Sharepreference的引用。在系統中共用一個sSharedPrefs,每個應該在擷取sp的時候都會将建立後sp加入到sSharedPrefs中以便後續進行通路。
在擷取sp的時候,如果通過sSharedPrefs擷取為空就會先建立一個sp,在new SharepreferenceImpl的時候,在構造函數中最後就會異步加載檔案到記憶體,異步開啟一個線程後就調用loadFromDiskLocked()函數進行加載:
SharepreferenceImpl.java
一旦加載完成後,就會notifyAll(),我們先看下get的操作
在get資料時,首先判斷檔案是否加載到記憶體,然後就直接讀取記憶體中的值,這裡可以看出一旦裝載了,那麼讀取的速度就很快。
上面SharepreferenceImpl是實作了get操作,真正的寫入是Editor接口來完成的,而EditorImpl是具體的實作類。其代碼如下:
首先檢視下存入的代碼:
存入的時候首先擷取同步鎖,然後将存入的資料放入EditorImpl中的一個mModified變量中,也就是存入的時候并沒有放入Sharepreference中,隻有在使用了apply或者commit後才真正存入。
下面來看看commit操作:
步驟1:
步驟2:
步驟3通知寫入資料發生變化
步驟4傳回寫入的結果。
代碼如下:
apply會将寫入放入到一個線程池中操作,這不會阻塞調用的線程。其他的都和commit類似。
QueuedWork.java
apply 與commit的對比
apply沒有傳回值, commit有傳回值能知道修改是否送出成功
apply是将修改送出到記憶體,再異步送出到磁盤檔案; commit是同步的送出到磁盤檔案;
多并發的送出commit時,需等待正在處理的commit資料更新到磁盤檔案後才會繼續往下執行,進而降低效率; 而apply隻是原子更新到記憶體,後調用apply函數會直接覆寫前面記憶體資料,從一定程度上提高很多效率。
擷取SP與Editor:
getSharedPreferences()是從ContextImpl.sSharedPrefsCache唯一的SPI對象;
edit()每次都是建立新的EditorImpl對象.
優化建議:
強烈建議不要在sp裡面存儲特别大的key/value, 有助于減少卡頓/anr
請不要高頻地使用apply, 盡可能地批量送出;commit直接在主線程操作, 更要注意了
不要使用MODE_MULTI_PROCESS;
高頻寫操作的key與高頻讀操作的key可以适當地拆分檔案, 由于減少同步鎖競争;
不要一上來就執行getSharedPreferences().edit(), 應該分成兩大步驟來做, 中間可以執行其他代碼.
不要連續多次edit(), 應該擷取一次擷取edit(),然後多次執行putxxx(), 減少記憶體波動; 經常看到大家喜歡封裝方法, 結果就導緻這種情況的出現.
每次commit時會把全部的資料更新的檔案, 是以整個檔案是不應該過大的, 影響整體性能;
<a href="http://gityuan.com/2017/06/18/SharedPreferences/">Gityuan部落格</a>
<a href="http://blog.csdn.net/yanbober/article/details/47866369">工匠若水</a>