SharedPreferences是一種輕型的Android數(shù)據(jù)存儲方式嘁锯,它的本質是基于XML文件存儲key-value鍵值對數(shù)據(jù)凰盔,通常用來存儲一些簡單的配置信息袋坑。它的存儲位置是在/data/data/<包名>/shared_prefs目錄下胜榔。SharedPreferences對象本身只能獲取數(shù)據(jù)而不支持存儲和修改桩盲,存儲修改是通過Editor對象實現(xiàn)寂纪。比較經(jīng)典的使用方式例如用戶輸入框對過往登錄賬戶的存儲。實現(xiàn)SharedPreferences存儲的步驟如下:
1赌结、根據(jù)Context獲取SharedPreferences對象
2捞蛋、利用edit()方法獲取Editor對象。
3柬姚、通過Editor對象存儲key-value鍵值對數(shù)據(jù)拟杉。
4、通過commit()或apply()方法提交數(shù)據(jù)量承。
那么問題來了搬设,commit和apply到底有什么區(qū)別呢,或者說我們如何選擇撕捍?
總結一下:
commit() 是直接同步地提交到硬件磁盤拿穴,因此,多個并發(fā)的采用 commit() 做提交的時候忧风,它們會等待正在處理的 commit() 保存到磁盤后再進行操作默色,從而降低了效率。而 apply() 只是原子的提交到內容狮腿,后面再調用 apply() 的函數(shù)進行異步操作腿宰。
翻源碼可以發(fā)現(xiàn) apply() 返回值為 void,而 commit() 返回一個 boolean 值代表是否提交成功缘厢。
apply() 方法不會有任何失敗的提示吃度。
但使用apply()就真的完美無缺嗎椿每。非也
上面說到,commit是直接同步地提交到硬件磁盤夜畴,apply只是原子的提交到內容拖刃,后面再調用 apply() 的函數(shù)進行異步操作。這里的后面贪绘,其實是在Activity的onPause的時候去執(zhí)行,這個時候會有一個問題央碟。我們知道税灌,Activity跳轉的時候均函,比如ActivityA跳轉到ActivityB,那么兩個Activity的生命周期是:A(onPause)-B(onCreat)-B(onStart)-B(onResume)-A(onStop)菱涤。如果我們在ActivityA的onPause中做了耗時操作苞也,將會導致Activity跳轉卡頓嚴重,甚至ANR粘秆。
也許有童鞋會說如迟,sp的加載不是在子線程么,怎么會卡住主線程攻走?子線程IO就一定不會阻塞主線程嗎殷勘?
sp為了避免同時讀寫,在操作的時候掛了一把鎖
private void awaitLoadedLocked() {
while (!mLoaded) {
try {
wait();
} catch (InterruptedException unused) {
}
}
}
這意味著昔搂,apply雖然開了子線程處理玲销,但是activity退出時會等待寫入完成 也可能造成anr。
所以摘符,我們在使用SP的時候贤斜,一定要仔細斟酌。不要濫用sp逛裤,非輕量級數(shù)據(jù)瘩绒,盡量避免使用sp來存儲。
而且在儲存多對數(shù)據(jù)時带族,不要多次commit锁荔。對實時性要求不高的數(shù)據(jù),盡量合并commit炉菲。避免如下錯誤寫法:
SharedPreferences sp = getSharedPreferences("test", MODE_PRIVATE);
sp.edit().putString("test1", "sss").apply();
sp.edit().putString("test2", "sss").apply();
sp.edit().putString("test3", "sss").apply();
sp.edit().putString("test4", "sss").apply();