應(yīng)用SharedPreferences在進(jìn)程之間通信時(shí)你會(huì)遇到的問題
出現(xiàn)這樣一個(gè)問題:先啟動(dòng)主線程并獲取SharedPreferences對(duì)象,然后對(duì)值進(jìn)行修改,然后再啟動(dòng)其它進(jìn)程并獲取SharedPreferences對(duì)象,能夠獲取修改后的值,但此時(shí)如果對(duì)此值進(jìn)行修改,均不能對(duì)其他進(jìn)程產(chǎn)生作用。必須等到進(jìn)程重啟或者app重啟才能與其他進(jìn)程進(jìn)行數(shù)據(jù)同步。
原因:只有在創(chuàng)建SharedPreferences對(duì)象的時(shí)候才會(huì)從磁盤中國進(jìn)行讀取,讀取完以后值保存在內(nèi)存(HashMap)當(dāng)中,下次獲取SharedPreferences對(duì)象優(yōu)先從緩存當(dāng)中獲取,所以在當(dāng)前進(jìn)程修改了SharedPreferences的值,其他進(jìn)程的SharedPreferences對(duì)象的值并不會(huì)改變。只有把當(dāng)前另外的進(jìn)程關(guān)閉(如:關(guān)閉手機(jī)、或殺死該app重新進(jìn)入),再次創(chuàng)建進(jìn)程時(shí)才會(huì)重新從磁盤中再次讀取文件。
源碼分析:通常我們獲取SharedPreferences都是通過Context中的getSharedPreference方法來獲取SharedPreferences對(duì)象,在Context中,getSharedPreference方法是一個(gè)抽象方法,沒有具體實(shí)現(xiàn)。我們知道Context的實(shí)現(xiàn)類是ContextImpl,所以直接找到ContextImpl的getSharedPreference方法??梢钥吹?,這里將SharedPreferences的實(shí)例對(duì)象SharedPreferencesImpl的先通過Map緩存起來,以后每次獲取如果內(nèi)存已經(jīng)存在,那么直接返回,如果不存在才會(huì)重新創(chuàng)建。
那么為什么在同一個(gè)進(jìn)程SharedPreferences應(yīng)用又沒有問題呢?
這是由于Editor 的實(shí)現(xiàn)類EditorImpl,但我們修改完SharedPreferences對(duì)象之后都會(huì)調(diào)用commit(直接當(dāng)錢線程執(zhí)行)或者apply方法(將當(dāng)前任務(wù)加到線程池中,后臺(tái)執(zhí)行)才會(huì)執(zhí)行保存,在源碼中可以看到無論調(diào)用哪一個(gè)方法都會(huì)調(diào)用commitToMemory()和enqueueDiskWrite方法。commitToMemory()方法就是將值提交到內(nèi)存當(dāng)中。enqueueDiskWrite()將修改后的內(nèi)容寫入到磁盤當(dāng)中。所以下一次取出的值是正確的。