SharedPreferences 進行的存儲會導(dǎo)致數(shù)據(jù)丟失?
最近由于需求迭代, K-V 的存儲方式加入了加解密流程, 然后上線后,發(fā)現(xiàn)依賴于SharedPreferences 進行緩存的頁面,發(fā)生了一些不可思議的報錯,仿佛SharedPreferences 沒有put數(shù)據(jù)到xml中一樣.一開始不太相信,后面分析了下,確實是這樣.
SharedPreferences 的commit 和apply?
commit 是同步提交, apply是異步處理. 為啥有這兩種區(qū)分呢,那是因為SharedPreferences 如果用commit 來存儲數(shù)據(jù),數(shù)據(jù)量針對大數(shù)據(jù)那種,很容易造成ANR,因為要數(shù)據(jù)落地才能夠進行后續(xù)相應(yīng)的操作的話.你可以想象一下. 而用了apply 這種異步的話, apply的原理是開多一份xml 來進行讀寫, 等數(shù)據(jù)真實落地后,再刪之前舊的那份xml. 那問題來了,既然這個過程是異步的,有沒有可能會造成數(shù)據(jù)丟失,或者數(shù)據(jù)不準(zhǔn)確呢? 答案是,確實如此.SharedPreferences 文件的加載使用了異步線程,而且加載線程并沒有設(shè)置優(yōu)先級,如果這個時候讀取數(shù)據(jù)就需要等待文件加載線程的結(jié)束。這就導(dǎo)致主線程等待低優(yōu)先線程鎖的問題,比如一個 100KB 的 SP 文件讀取等待時間大約需要 50 ~ 100ms,并且建議大家提前用預(yù)加載啟動過程用到的 SP 文件。而且重要的一點,無論是commit 還是apply ,他在讀寫的過程都是全量寫入的.
SharedPreferences 的IO是否安全?
既然SharedPreferences 是要讀寫xml來進行數(shù)據(jù)存儲和讀取的,那么這個IO操作是否安全呢,在java里, IO操作都會帶上execption 拋出相應(yīng)的IO異常, 關(guān)于SharedPreferences也是一樣的.如圖:所以其中的數(shù)據(jù)讀取量,根據(jù)相應(yīng)的流而議,文件越大,那么相應(yīng)的風(fēng)險也就越大啦.因此SharedPreferences 也只適合那種輕量級的數(shù)據(jù)流的讀寫.
SharedPreferences 在線程間的表現(xiàn)如何?
首先看入?yún)?
方法是線程安全的, 但是跨線程呢? 如果你用了MODE_MULTI_PROCESS 的話,那別的線程就可以更改你的數(shù)據(jù)啦.但是如果你不用這種方式的話, 那數(shù)據(jù)就不能給到別的線程去讀寫,因此,這個流程,大家可以腦補一下.
那么如何處理呢?
1.不用用SharedPreferences 保存跳轉(zhuǎn)入口的緩存,而應(yīng)該利用Intent 去傳遞相應(yīng)數(shù)據(jù)到Activity 或者Fragment.
2.不要存儲大數(shù)據(jù), 包括一些加解密,因為加密操作會導(dǎo)致string 的長度變大, 如果都是加密存儲,那么內(nèi)容可想而知.
3.可以區(qū)分用戶級別數(shù)據(jù)和應(yīng)用級別數(shù)據(jù)來進行處理,如果用戶數(shù)據(jù)較大, 可以考慮一些開源庫如MMKV,如果較小,需要加密處理保證安全的話,針對部分字段進行加解密即可.
4.應(yīng)用盡量不要過分依賴SharedPreferences來進行相應(yīng)的業(yè)務(wù)邏輯處理操作.考慮一些設(shè)計模式來避免這個過程吧.