摘要:概述可以通過(guò)獲取到,它是一個(gè)接口,實(shí)現(xiàn)在源碼也僅僅只有行,相對(duì)于龐大的源碼,小很多。但是你真的了解它嗎問(wèn)題不同的里面獲取的相同嗎支持并發(fā)嗎直接保存了嗎針對(duì)上面的問(wèn)題,我們一點(diǎn)點(diǎn)來(lái)分析。但是僅僅是保存到了中,正真的是要在或之后。
概述說(shuō)在前面:SharedPreferences是Android中幾種重要的存儲(chǔ)數(shù)據(jù)的方式,Android開(kāi)發(fā)不會(huì)沒(méi)有人從來(lái)沒(méi)有使用過(guò),但是卻很好人會(huì)關(guān)注它是怎么實(shí)現(xiàn)的,確實(shí)SharedPreferences實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,本質(zhì)是基于文件存儲(chǔ),格式是XML形勢(shì)的,本篇文章并沒(méi)有太深的技術(shù),但絕對(duì)是不可缺少的知識(shí)。
SharedPreferences可以通過(guò)Context獲取到,它是一個(gè)接口,實(shí)現(xiàn)在frameworksbasecorejavaandroidappSharedPreferencesImpl.java
源碼也僅僅只有630行,相對(duì)于龐大的Android源碼,小很多。但是你真的了解它嗎?
問(wèn)題1、不同的Activity里面Context.getSharedPreferences()獲取的SharedPreferences相同嗎?
2、支持并發(fā)嗎?
3、SharedPreferences.putXXX()直接保存了嗎?
......
針對(duì)上面的問(wèn)題,我們一點(diǎn)點(diǎn)來(lái)分析。
獲得SharedPreferences我們獲得SharedPreferences是通過(guò)Context.getSharedPreferences(),源碼如下:
@Override public SharedPreferences getSharedPreferences(String name, int mode) { SharedPreferencesImpl sp; synchronized (ContextImpl.class) { // 靜態(tài)的 全局唯一,緩存得到的SharedPreferences,key是app包名 if (sSharedPrefs == null) { sSharedPrefs = new ArrayMap創(chuàng)建SharedPreferences>(); } // 通過(guò)每一個(gè)app的包名緩存不同的SharedPreferences,key是文件名 // 這里就明白前面提到的第一個(gè)問(wèn)題了,一個(gè)文件對(duì)應(yīng)一個(gè)SharedPreferences final String packageName = getPackageName(); ArrayMap packagePrefs = sSharedPrefs.get(packageName); if (packagePrefs == null) { packagePrefs = new ArrayMap (); sSharedPrefs.put(packageName, packagePrefs); } // 略... // 如果以創(chuàng)建過(guò),直接從緩存中獲取返回 sp = packagePrefs.get(name); if (sp == null) { // 如果沒(méi)有創(chuàng)建一個(gè) 文件名為data/data/packege/shared_prefs/xxx.xml File prefsFile = getSharedPrefsFile(name); sp = new SharedPreferencesImpl(prefsFile, mode); // 創(chuàng)建實(shí)例對(duì)象 packagePrefs.put(name, sp); // 放到緩存中 return sp; } } // 略... return sp; }
SharedPreferences的創(chuàng)建很簡(jiǎn)單,我們先看看構(gòu)造方法:
// 僅有一個(gè) SharedPreferencesImpl(File file, int mode) { mFile = file; mBackupFile = makeBackupFile(file); // 創(chuàng)建備份 mMode = mode; mLoaded = false; mMap = null; // 存放鍵值對(duì)的map startLoadFromDisk(); // 從本地load出來(lái) }
從構(gòu)造函數(shù)我們不難看出,SharedPreferences實(shí)際是以Map(HashMap)存儲(chǔ)數(shù)據(jù),創(chuàng)建的時(shí)候就從本地文件中讀取數(shù)據(jù)到內(nèi)存中,所以,不能存儲(chǔ)太多的數(shù)據(jù) ,否則內(nèi)存會(huì)爆掉的哦。
讀取本地文件中的數(shù)據(jù)當(dāng)實(shí)例化的時(shí)候就會(huì)觸發(fā),一個(gè)讀取本地已存儲(chǔ)的數(shù)據(jù),
private void loadFromDiskLocked() { // 讀取過(guò)就不在讀取 if (mLoaded) { return; } //... Map map = null; StructStat stat = null; try { // 存儲(chǔ)文件狀態(tài) stat = Os.stat(mFile.getPath()); if (mFile.canRead()) { BufferedInputStream str = null; try { str = new BufferedInputStream( new FileInputStream(mFile), 16*1024); // 格式為xml,解析xml得到map 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) { } // 加載過(guò)后更改狀態(tài),如果沒(méi)有創(chuàng)建一個(gè)HashMap mLoaded = true; if (map != null) { mMap = map; mStatTimestamp = stat.st_mtime; mStatSize = stat.st_size; } else { mMap = new HashMap獲得存儲(chǔ)的數(shù)據(jù)(); } notifyAll(); }
得到數(shù)據(jù)通常是getXXX(),實(shí)際很簡(jiǎn)單,就是存map中取數(shù)據(jù)。
// 已getString()為例,其他一樣 @Nullable public String getString(String key, @Nullable String defValue) { // 同步哦 synchronized (this) { // 確保,已從文件中讀取過(guò)數(shù)據(jù) awaitLoadedLocked(); // 從map中的得到數(shù)據(jù) String v = (String)mMap.get(key); return v != null ? v : defValue; } }保存數(shù)據(jù)
大家都知道保存數(shù)據(jù)是通過(guò)Editor來(lái)存儲(chǔ)的,事實(shí)上也確實(shí)是這樣的。但是putXXX()僅僅是保存到了map中,正真的是要在commit()或apply()之后。
public Editor putString(String key, @Nullable String value) { // 同步哦 synchronized (this) { mModified.put(key, value); return this; } }
1、
public boolean commit() { MemoryCommitResult mcr = commitToMemory(); // 寫(xiě)數(shù)據(jù) SharedPreferencesImpl.this.enqueueDiskWrite( mcr, null /* sync write on this thread okay */); try { mcr.writtenToDiskLatch.await(); } catch (InterruptedException e) { return false; } notifyListeners(mcr); return mcr.writeToDiskResult; }
2、
private void enqueueDiskWrite(final MemoryCommitResult mcr, final Runnable postWriteRunnable) { final Runnable writeToDiskRunnable = new Runnable() { public void run() { synchronized (mWritingToDiskLock) { // 往文件中寫(xiě)入數(shù)據(jù) writeToFile(mcr); } synchronized (SharedPreferencesImpl.this) { mDiskWritesInFlight--; } if (postWriteRunnable != null) { postWriteRunnable.run(); } } }; // ... QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable); }
3、
// Note: must hold mWritingToDiskLock private void writeToFile(MemoryCommitResult mcr) { // ... try { FileOutputStream str = createFileOutputStream(mFile); if (str == null) { mcr.setDiskWriteResult(false); return; } // 寫(xiě)入到文件中 XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str); FileUtils.sync(str); str.close(); ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0); try { // 更新文件的狀態(tài) 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(); 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 file if (mFile.exists()) { if (!mFile.delete()) { Log.e(TAG, "Couldn"t clean up partially-written file " + mFile); } } mcr.setDiskWriteResult(false); }總結(jié)
1、SharedPreferences有緩存
2、數(shù)據(jù)是通過(guò)map來(lái)快速訪問(wèn),所以不用擔(dān)心文件IO耗時(shí)
3、支持多線程并發(fā)
4、本質(zhì)是基于文件xml的形式
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66790.html
摘要:真正要做高性能的系統(tǒng),不僅需要在數(shù)據(jù)結(jié)構(gòu)與算法層面深入,更要從硬件操作系統(tǒng)文件系統(tǒng)底層原理等多個(gè)領(lǐng)域做更多的研究例如阿里云自研的系統(tǒng)使用了裸盤(pán)技術(shù)。 《CDN之我見(jiàn)》共由三個(gè)篇章組成,分為原理篇、詳解篇和隕坑篇。本篇章適合那些從未接觸過(guò)、或僅了解一些 CDN 專(zhuān)業(yè)術(shù)語(yǔ),想深入了解和感受 CDN 究竟是什么的同學(xué)。本次由白金老師繼續(xù)為大家分享《CDN之我見(jiàn)》系列二,主要講解緩存是什么、工...
摘要:真正要做高性能的系統(tǒng),不僅需要在數(shù)據(jù)結(jié)構(gòu)與算法層面深入,更要從硬件操作系統(tǒng)文件系統(tǒng)底層原理等多個(gè)領(lǐng)域做更多的研究例如阿里云自研的系統(tǒng)使用了裸盤(pán)技術(shù)。 《CDN之我見(jiàn)》共由三個(gè)篇章組成,分為原理篇、詳解篇和隕坑篇。本篇章適合那些從未接觸過(guò)、或僅了解一些 CDN 專(zhuān)業(yè)術(shù)語(yǔ),想深入了解和感受 CDN 究竟是什么的同學(xué)。本次由白金老師繼續(xù)為大家分享《CDN之我見(jiàn)》系列二,主要講解緩存是什么、工...
摘要:在我們寫(xiě)項(xiàng)目代碼的過(guò)程中,要經(jīng)常請(qǐng)求接口數(shù)據(jù),在某些異步請(qǐng)求數(shù)據(jù)之后,將得到的值進(jìn)行處理。 在我們寫(xiě)項(xiàng)目代碼的過(guò)程中,要經(jīng)常請(qǐng)求接口數(shù)據(jù),在某些異步請(qǐng)求數(shù)據(jù)之后,將得到的值進(jìn)行處理。通俗的一句話就是,我要把這個(gè)值放到另一個(gè)函數(shù)中,按行數(shù)順序處理,即同步的概念! 例子:第一步,涉及異步函數(shù) 假設(shè)我有一個(gè)函數(shù)abc, function abc(){ //異步方法,請(qǐng)求數(shù)據(jù)得到re...
摘要:通過(guò)我們可以更輕松地入門(mén),更簡(jiǎn)單的使用的框架。團(tuán)隊(duì)為了擺脫框架中各類(lèi)繁復(fù)紛雜的配置,使用約定優(yōu)于配置的思想,在基礎(chǔ)上整合了大量常用的第三方庫(kù)的開(kāi)發(fā)框架。這里還要說(shuō)的一點(diǎn),的出現(xiàn)并不是單純的為了簡(jiǎn)化開(kāi)發(fā),更是為做鋪墊。 說(shuō)完了Spring 我們來(lái)聊聊Spring的進(jìn)階版Spring Boot,如果你還不知道Spring Boot,那希望這篇文章能夠?yàn)槟阒该鞣较颉?Spring Boot ...
閱讀 1663·2021-08-13 15:03
閱讀 2096·2019-08-30 15:54
閱讀 3554·2019-08-26 10:30
閱讀 1030·2019-08-26 10:22
閱讀 2756·2019-08-23 14:42
閱讀 1815·2019-08-22 11:16
閱讀 1046·2019-08-21 18:33
閱讀 3172·2019-08-21 17:28