日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android-带你从源码角度理解SharedPreferences存储原理

發(fā)布時(shí)間:2024/9/30 Android 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android-带你从源码角度理解SharedPreferences存储原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

SP的特點(diǎn)以及基本使用方式

SharedPreferences因非常適合存儲(chǔ)較小鍵值集合數(shù)據(jù)且使用非常簡(jiǎn)單的特點(diǎn),而受到廣大程序員們熱愛(ài)。
SP使用非常簡(jiǎn)單:

//讀操作 Context context = getActivity(); SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE); String result = sp.getString("key", "defaultValue");//寫(xiě)操作 Context context = getActivity(); SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE); sp.edit().putString("key", "value").commit();

SP源碼分析

SP是如何讀取數(shù)據(jù)的

其實(shí)Context實(shí)現(xiàn)就是ContextImpl中,要想搞清楚SP是如何讀取數(shù)據(jù)的,第一步當(dāng)然是要了解ContextImpl.getSharedPreferences方法是如何實(shí)現(xiàn)的

/*** Map from package name, to preference name, to cached preferences.*///緩存所有應(yīng)用的SP容器,該容器key對(duì)應(yīng)應(yīng)用名稱,value則為每個(gè)應(yīng)用存儲(chǔ)所有sp的容器(ArrayMap)private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;@Overridepublic SharedPreferences getSharedPreferences(String name, int mode) {SharedPreferencesImpl sp;synchronized (ContextImpl.class) {if (sSharedPrefs == null) {//如果靜態(tài)對(duì)象不存在,直接創(chuàng)建一個(gè)Map,以便后期用于保存spsSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();}//獲取當(dāng)前應(yīng)用包名final String packageName = getPackageName();//從保存sp的容器中通過(guò)包名查找當(dāng)前應(yīng)用所有sp;每個(gè)app的所有sp都是保存在ArrayMap中,ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);if (packagePrefs == null) {//如果從sp容器沒(méi)找到保存當(dāng)前應(yīng)用sp的ArrayMap直接創(chuàng)建一個(gè)packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();//將創(chuàng)建的對(duì)象保存到sp容器中sSharedPrefs.put(packageName, packagePrefs);}// At least one application in the world actually passes in a null// name. This happened to work because when we generated the file name// we would stringify it to "null.xml". Nice.if (mPackageInfo.getApplicationInfo().targetSdkVersion <Build.VERSION_CODES.KITKAT) {//如果targetSdk版本好小于19,且傳入的文件名為null的話,默認(rèn)將文件名命名為"null"if (name == null) {name = "null";}}//從當(dāng)前應(yīng)用的sp容器中通過(guò)文件名去查找spsp = packagePrefs.get(name);if (sp == null) {//如果沒(méi)找到,直接創(chuàng)建一個(gè)文件名以name命名的xml文件File prefsFile = getSharedPrefsFile(name);//此處極為關(guān)鍵,該構(gòu)造器是讀取文件操作sp = new SharedPreferencesImpl(prefsFile, mode);//將創(chuàng)建sp對(duì)象保存到當(dāng)前應(yīng)用sp容器中packagePrefs.put(name, sp);return sp;}}if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {// If somebody else (some other process) changed the prefs// file behind our back, we reload it. This has been the// historical (if undocumented) behavior.//如果讀取模式是跨線程或targetSdk版本小于11,再次重新load下文件而已sp.startReloadIfChangedUnexpectedly();}return sp;}

從上面源碼可以看出,getSharedPreferences方法是先根據(jù)當(dāng)前應(yīng)用名稱來(lái)獲取一個(gè)ArrayMap(存儲(chǔ)sp的容器)如果沒(méi)有直接創(chuàng)建并保存到內(nèi)存中,然后再根據(jù)文件名來(lái)獲取SharedPreferencesImpl的對(duì)象(沒(méi)找到則直接創(chuàng)建SharedPreferencesImpl),這短短的三十幾行代碼還是比較簡(jiǎn)單的。
因?yàn)槭庆o態(tài)變量存儲(chǔ)鍵值數(shù)據(jù)的所以我們用SP存儲(chǔ)的數(shù)據(jù)在內(nèi)存中是一直存在;所以我們盡量用一個(gè)文件來(lái)存在數(shù)據(jù),以達(dá)到減少內(nèi)存對(duì)象

大家可以看到getSharePreferences返回的對(duì)象類型其實(shí)是SharedPreferencesImpl類型,只不過(guò)該類實(shí)現(xiàn)了SharedPreferences接口而已,接下來(lái)我們先看看SharedPreferencesImpl構(gòu)造器做了啥東東。

SharedPreferencesImpl.java

final class SharedPreferencesImpl implements SharedPreferences {private final File mFile;private final File mBackupFile;private final int mMode;private Map<String, Object> mMap; // guarded by 'this'private int mDiskWritesInFlight = 0; // guarded by 'this'//文件是否加載成功private boolean mLoaded = false; // guarded by 'this'//文件的時(shí)間以及大小private long mStatTimestamp; // guarded by 'this'private long mStatSize; // guarded by 'this'private final Object mWritingToDiskLock = new Object();private static final Object mContent = new Object();private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =new WeakHashMap<OnSharedPreferenceChangeListener, Object>();SharedPreferencesImpl(File file, int mode) {//給類成員變量賦值mFile = file;mBackupFile = makeBackupFile(file);mMode = mode;mLoaded = false;mMap = null;//開(kāi)啟一個(gè)線程讀取文件startLoadFromDisk();}private static File makeBackupFile(File prefsFile) {return new File(prefsFile.getPath() + ".bak");}private void startLoadFromDisk() {synchronized (this) {//使用同步代碼代碼塊,對(duì)mloader進(jìn)行賦值mLoaded = false;}//開(kāi)啟線程讀取文件new Thread("SharedPreferencesImpl-load") {public void run() {synchronized (SharedPreferencesImpl.this) {loadFromDiskLocked();}}}.start();}private void loadFromDiskLocked() {//如果文件已經(jīng)加載完畢直接返回if (mLoaded) {return;}if (mBackupFile.exists()) {mFile.delete();mBackupFile.renameTo(mFile);}// Debuggingif (mFile.exists() && !mFile.canRead()) {Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission");}Map map = null;StructStat stat = null;try {stat = Os.stat(mFile.getPath());if (mFile.canRead()) {//讀取文件BufferedInputStream str = null;try {str = new BufferedInputStream(new FileInputStream(mFile), 16*1024);//使用XmlUtils工具類讀取xml文件數(shù)據(jù)map = XmlUtils.readMapXml(str);} catch (XmlPullParserException e) {Log.w(TAG, "getSharedPreferences", e);} catch (FileNotFoundException e) {Log.w(TAG, "getSharedPreferences", e);} catch (IOException e) {Log.w(TAG, "getSharedPreferences", e);} finally {IoUtils.closeQuietly(str);}}} catch (ErrnoException e) {}//修改文件加載完成標(biāo)志mLoaded = true;if (map != null) {mMap = map;//如果有數(shù)據(jù),將數(shù)據(jù)已經(jīng)賦值給類成員變量mMap,mStatTimestamp = stat.st_mtime;//記錄文件上次修改時(shí)間mStatSize = stat.st_size;//記錄文件大小(字節(jié)單位)} else {//沒(méi)有數(shù)據(jù)直接創(chuàng)建一個(gè)hashmap對(duì)象mMap = new HashMap<String, Object>();}//此處非常關(guān)鍵是為了通知其他線程文件已讀取完畢,你們可以執(zhí)行讀/寫(xiě)操作了notifyAll();}}

通過(guò)上述分析我們不難發(fā)現(xiàn)調(diào)用getSharedPreferences方法就已經(jīng)開(kāi)啟一個(gè)線程去讀取文件了
我們?cè)賮?lái)看看SharedPreferencesImpl.getString內(nèi)部是如何執(zhí)行的

@Nullable public String getString(String key, @Nullable String defValue) {synchronized (this) {//此處會(huì)阻塞當(dāng)前線程,直到文件讀取完畢awaitLoadedLocked();//從類成員變量mMap中直接讀取數(shù)據(jù),沒(méi)有直接返回默認(rèn)值String v = (String)mMap.get(key);return v != null ? v : defValue;} }private void awaitLoadedLocked() {if (!mLoaded) {// Raise an explicit StrictMode onReadFromDisk for this// thread, since the real read will be in a different// thread and otherwise ignored by StrictMode.BlockGuard.getThreadPolicy().onReadFromDisk();}//如果文件未加載完畢,會(huì)一直阻塞當(dāng)前線程,直到加載完成為止while (!mLoaded) {try {wait();} catch (InterruptedException unused) {}}}

至此關(guān)于SP的讀操作以全部分析完畢,相信大家對(duì)SP讀操作有了更深入的認(rèn)識(shí)了;下面我們繼續(xù)再看看SP的寫(xiě)操作是怎么玩的

SP是如何寫(xiě)入數(shù)據(jù)的

通常寫(xiě)數(shù)據(jù)大體是這樣的

//寫(xiě)操作 Context context = getActivity(); SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE); sp.edit().putString("key", "value").commit();

getSharedPreferences大家都很清楚了,我們現(xiàn)在edit方法到底做了什么

public Editor edit() {// TODO: remove the need to call awaitLoadedLocked() when// requesting an editor. will require some work on the// Editor, but then we should be able to do://// context.getSharedPreferences(..).edit().putString(..).apply()//// ... all without blocking.synchronized (this) {awaitLoadedLocked();}return new EditorImpl(); }

可以看到edit方法非常簡(jiǎn)單,首先是通過(guò)同步代碼塊調(diào)用了awaitLoadedLocked方法,緊接著直接返回了一個(gè)EditorImpl實(shí)例對(duì)象,我們繼續(xù)追蹤看看EditorImpl類是put、commit方法

public final class EditorImpl implements Editor {private final Map<String, Object> mModified = Maps.newHashMap();private boolean mClear = false;public Editor putString(String key, @Nullable String value) {synchronized (this) {mModified.put(key, value);return this;}}public Editor remove(String key) {synchronized (this) {//注意此處并沒(méi)有執(zhí)行刪除操作,而是將其對(duì)應(yīng)key的value設(shè)置了當(dāng)前this//commitToMemory方法中會(huì)對(duì)此做特殊處理mModified.put(key, this);return this;}}public Editor clear() {synchronized (this) {mClear = true;return this;}}public boolean commit() {//第一步 commitToMemory方法可以理解為對(duì)SP中的mMap對(duì)象同步到最新數(shù)據(jù)狀態(tài)MemoryCommitResult mcr = commitToMemory();//第二步 寫(xiě)文件;注意第二個(gè)參數(shù)為null,寫(xiě)文件操作會(huì)運(yùn)行在當(dāng)前線程SharedPreferencesImpl.this.enqueueDiskWrite(mcr, null /* sync write on this thread okay */);try {mcr.writtenToDiskLatch.await();} catch (InterruptedException e) {return false;}//第三步 通知監(jiān)聽(tīng)器數(shù)據(jù)改變notifyListeners(mcr);//第四步 返回寫(xiě)操作狀態(tài)return mcr.writeToDiskResult;}... }

從上面可以看到,其實(shí)putXXX方法知識(shí)把鍵值數(shù)據(jù)先存放到內(nèi)存中去了(mModified對(duì)象中);比較有意思到是remove、clear方法,remove方法會(huì)將要?jiǎng)h除的數(shù)據(jù)的value設(shè)置為EditorImpl自己(commitToMemory方法會(huì)對(duì)此做特殊處理);
clear方法也僅僅是設(shè)置一個(gè)標(biāo)志位而已(commitToMemory方法中用到);
最關(guān)鍵的方法還是commit方法,我們可以看到其實(shí)commit方法主要分為四步,第一步將sp數(shù)據(jù)同步到最新?tīng)顟B(tài)并返回mcr對(duì)象;第二步將mcr對(duì)象中數(shù)據(jù)寫(xiě)入文件;第三步通知監(jiān)聽(tīng)器數(shù)據(jù)已發(fā)生改變;最后一步就是返回寫(xiě)操作狀態(tài)是否成功

public final class EditorImpl implements Editor {//可以最后看,和commit主要區(qū)別就是apply的寫(xiě)文件操作會(huì)在一個(gè)線程中執(zhí)行,不會(huì)阻塞UI線程public void apply() {final MemoryCommitResult mcr = commitToMemory();final Runnable awaitCommit = new Runnable() {public void run() {try {mcr.writtenToDiskLatch.await();} catch (InterruptedException ignored) {}}};//將awaitCommit任務(wù)提交到一個(gè)隊(duì)列中QueuedWork.add(awaitCommit);Runnable postWriteRunnable = new Runnable() {public void run() {//寫(xiě)文件操作完成后會(huì)執(zhí)行此2行代碼(如果寫(xiě)操作未結(jié)束,當(dāng)前頁(yè)面已經(jīng)銷毀寫(xiě)操作的數(shù)據(jù)會(huì)丟失?這個(gè)切入點(diǎn)主要看QueuedWork的waitToFinish方法何時(shí)調(diào)用就明白了,有興趣同學(xué)可以自己研究下)awaitCommit.run();//移除任務(wù)QueuedWork.remove(awaitCommit);}};SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);// Okay to notify the listeners before it's hit disk// because the listeners should always get the same// SharedPreferences instance back, which has the// changes reflected in memory.notifyListeners(mcr);}// Returns true if any changes were madeprivate MemoryCommitResult commitToMemory() {//創(chuàng)建一個(gè)對(duì)象MemoryCommitResult mcr = new MemoryCommitResult();synchronized (SharedPreferencesImpl.this) {// We optimistically don't make a deep copy until// a memory commit comes in when we're already// writing to disk.if (mDiskWritesInFlight > 0) {// We can't modify our mMap as a currently// in-flight write owns it. Clone it before// modifying it.// noinspection uncheckedmMap = new HashMap<String, Object>(mMap);}mcr.mapToWriteToDisk = mMap;mDiskWritesInFlight++;//如果sp注冊(cè)了多個(gè)監(jiān)聽(tīng)器,將其賦值給mcr對(duì)象boolean hasListeners = mListeners.size() > 0;if (hasListeners) {mcr.keysModified = new ArrayList<String>();mcr.listeners =new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());}synchronized (this) {//如果調(diào)用了clear方法,判斷sp中mMap是否為空,不為空直接清空數(shù)據(jù),并設(shè)置標(biāo)志位,表示數(shù)據(jù)有改變; 此操作只會(huì)清空上次數(shù)據(jù),不會(huì)對(duì)清空本次數(shù)據(jù)if (mClear) {if (!mMap.isEmpty()) {mcr.changesMade = true;mMap.clear();}mClear = false;}//遍歷需要修改數(shù)據(jù)的鍵值集合for (Map.Entry<String, Object> e : mModified.entrySet()) {String k = e.getKey();Object v = e.getValue();// "this" is the magic value for a removal mutation. In addition,// setting a value to "null" for a given key is specified to be// equivalent to calling remove on that key.//如果對(duì)應(yīng)的值為它自己EditorImpl或?yàn)閚ullif (v == this || v == null) {//如果sp的數(shù)據(jù)結(jié)合沒(méi)有該鍵值對(duì),直接進(jìn)入下一個(gè)循環(huán)if (!mMap.containsKey(k)) {continue;}//有該鍵值集合直接刪除,因?yàn)閞emove方法其實(shí)存放的就是EditorImpl對(duì)象mMap.remove(k);} else {//將要寫(xiě)入的鍵值數(shù)據(jù),同步到sp的mMap中if (mMap.containsKey(k)) {Object existingValue = mMap.get(k);if (existingValue != null && existingValue.equals(v)) {continue;}}mMap.put(k, v);}//標(biāo)志數(shù)據(jù)發(fā)生改變mcr.changesMade = true;if (hasListeners) {mcr.keysModified.add(k);}}//結(jié)尾清空EditorImpl中mModified數(shù)據(jù)mModified.clear();}}return mcr;}private void notifyListeners(final MemoryCommitResult mcr) {//注意監(jiān)聽(tīng)器的回調(diào)方法都是在UI線程執(zhí)行的if (mcr.listeners == null || mcr.keysModified == null ||mcr.keysModified.size() == 0) {return;}if (Looper.myLooper() == Looper.getMainLooper()) {for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {final String key = mcr.keysModified.get(i);for (OnSharedPreferenceChangeListener listener : mcr.listeners) {if (listener != null) {listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);}}}} else {// Run this function on the main thread.ActivityThread.sMainThreadHandler.post(new Runnable() {public void run() {notifyListeners(mcr);}});}} }// Return value from EditorImpl#commitToMemory() private static class MemoryCommitResult {public boolean changesMade; // any keys different?public List<String> keysModified; // may be nullpublic Set<OnSharedPreferenceChangeListener> listeners; // may be nullpublic Map<?, ?> mapToWriteToDisk;//一個(gè)計(jì)數(shù)器,用來(lái)實(shí)現(xiàn)寫(xiě)文件線程通知其他線程寫(xiě)操作已經(jīng)完成的功能,public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);//本次寫(xiě)操作狀態(tài)結(jié)果public volatile boolean writeToDiskResult = false;public void setDiskWriteResult(boolean result) {writeToDiskResult = result;writtenToDiskLatch.countDown();} }SharePreferenceImpl.java /*** Enqueue an already-committed-to-memory result to be written* to disk.** They will be written to disk one-at-a-time in the order* that they're enqueued.** @param postWriteRunnable if non-null, we're being called* from apply() and this is the runnable to run after* the write proceeds. if null (from a regular commit()),* then we're allowed to do this disk write on the main* thread (which in addition to reducing allocations and* creating a background thread, this has the advantage that* we catch them in userdebug StrictMode reports to convert* them where possible to apply() ...)*/ private void enqueueDiskWrite(final MemoryCommitResult mcr,final Runnable postWriteRunnable) {final Runnable writeToDiskRunnable = new Runnable() {public void run() {synchronized (mWritingToDiskLock) {//持有mWritingToDiskLock鎖后,執(zhí)行寫(xiě)文件操作writeToFile(mcr);}synchronized (SharedPreferencesImpl.this) {//寫(xiě)操作數(shù)減一mDiskWritesInFlight--;}if (postWriteRunnable != null) {//文件寫(xiě)入操作完成后,執(zhí)行后續(xù)動(dòng)作;apply方法會(huì)執(zhí)行到次postWriteRunnable.run();}}};//判斷是不是調(diào)用commit方法final boolean isFromSyncCommit = (postWriteRunnable == null);// Typical #commit() path with fewer allocations, doing a write on// the current thread.if (isFromSyncCommit) {boolean wasEmpty = false;synchronized (SharedPreferencesImpl.this) {wasEmpty = mDiskWritesInFlight == 1;}if (wasEmpty) {//如果是commit方法,直接在當(dāng)前線程執(zhí)行;可以看出如果當(dāng)前是UI線程,會(huì)阻塞UI線程,引起界面卡頓writeToDiskRunnable.run();return;}}//如果不是commit是apply方法,writeToDiskRunnable任務(wù)會(huì)被提交到一個(gè)單個(gè)線程的線程池中執(zhí)行QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable); }// Note: must hold mWritingToDiskLock private void writeToFile(MemoryCommitResult mcr) {// Rename the current file so it may be used as a backup during the next readif (mFile.exists()) {//如果文件存在且數(shù)據(jù)未發(fā)生改變,沒(méi)有必要執(zhí)行無(wú)用的寫(xiě)入操作,直接通知并返回即可if (!mcr.changesMade) {// If the file already exists, but no changes were// made to the underlying map, it's wasteful to// re-write the file. Return as if we wrote it// out.mcr.setDiskWriteResult(true);return;}//文件存在且備份文件不存在if (!mBackupFile.exists()) {//嘗試將文件設(shè)置為備份文件(重命名)(此時(shí)只有備份文件,mFile對(duì)應(yīng)的文件已經(jīng)沒(méi)有了);如果操作不成功,通知并返回;因?yàn)橄旅娴讲僮魇菍?xiě)入數(shù)據(jù)到mFile中,所以我們先要備份數(shù)據(jù),這樣即使寫(xiě)入數(shù)據(jù)失敗時(shí),我們還可以使用備份數(shù)據(jù)if (!mFile.renameTo(mBackupFile)) {Log.e(TAG, "Couldn't rename file " + mFile+ " to backup file " + mBackupFile);mcr.setDiskWriteResult(false);return;}} else {//如果備份文件存在,直接刪除mFile,因?yàn)榻酉聛?lái)要重新寫(xiě)入mFile了mFile.delete();}}// Attempt to write the file, delete the backup and return true as atomically as// possible. If any exception occurs, delete the new file; next time we will restore// from the backup.try {//創(chuàng)建一個(gè)文件輸出流,用于寫(xiě)入數(shù)據(jù)到mFile中FileOutputStream str = createFileOutputStream(mFile);if (str == null) {//創(chuàng)建失敗直接返回mcr.setDiskWriteResult(false);return;}//寫(xiě)入數(shù)據(jù)到mFile中XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);//同步到硬盤(pán)中FileUtils.sync(str);//關(guān)閉流,釋放資源str.close();ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);try {final StructStat stat = Os.stat(mFile.getPath());synchronized (this) {//更新文件屬性mStatTimestamp = stat.st_mtime;mStatSize = stat.st_size;}} catch (ErrnoException e) {// Do nothing}// Writing was successful, delete the backup file if there is one.mBackupFile.delete();//寫(xiě)入數(shù)據(jù)成功,則刪除備份文件;因?yàn)樗袛?shù)據(jù)都寫(xiě)入mFile中mcr.setDiskWriteResult(true);return;} catch (XmlPullParserException e) {Log.w(TAG, "writeToFile: Got exception:", e);} catch (IOException e) {Log.w(TAG, "writeToFile: Got exception:", e);}// Clean up an unsuccessfully written fileif (mFile.exists()) {//寫(xiě)入過(guò)程中出現(xiàn)異常則刪除mFile,下次可以直接從備份文件中讀取if (!mFile.delete()) {Log.e(TAG, "Couldn't clean up partially-written file " + mFile);}}mcr.setDiskWriteResult(false); }private static FileOutputStream createFileOutputStream(File file) {FileOutputStream str = null;try {str = new FileOutputStream(file);} catch (FileNotFoundException e) {File parent = file.getParentFile();if (!parent.mkdir()) {Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);return null;}FileUtils.setPermissions(parent.getPath(),FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,-1, -1);try {str = new FileOutputStream(file);} catch (FileNotFoundException e2) {Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);}}return str; }void startReloadIfChangedUnexpectedly() {synchronized (this) {// TODO: wait for any pending writes to disk?if (!hasFileChangedUnexpectedly()) {return;}//可以看到如果被文件被別的進(jìn)程修改過(guò),重新加載下文件而已startLoadFromDisk();} }// Has the file changed out from under us? i.e. writes that // we didn't instigate. //判斷文件是不是已經(jīng)被別人(別的進(jìn)程)修改了? private boolean hasFileChangedUnexpectedly() {synchronized (this) {if (mDiskWritesInFlight > 0) {// If we know we caused it, it's not unexpected.if (DEBUG) Log.d(TAG, "disk write in flight, not unexpected.");//如果是自己修改,直接返回falsereturn false;}}final StructStat stat;try {/** Metadata operations don't usually count as a block guard* violation, but we explicitly want this one.*/BlockGuard.getThreadPolicy().onReadFromDisk();stat = Os.stat(mFile.getPath());} catch (ErrnoException e) {return true;}//根據(jù)文件上次修改時(shí)間以及大小二個(gè)屬性來(lái)判讀是否別的進(jìn)程修改過(guò)synchronized (this) {return mStatTimestamp != stat.st_mtime || mStatSize != stat.st_size;} }

相信大家應(yīng)該SP的讀寫(xiě)有了更深刻的認(rèn)識(shí)!

總結(jié)

以上是生活随笔為你收集整理的Android-带你从源码角度理解SharedPreferences存储原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。