Android—数据持久化、SP源码
3種數(shù)據(jù)持久化:
- File:openFileInput(String fileName)、openFileOutput(String fileName, int mode)
不對(duì)存儲(chǔ)的內(nèi)容進(jìn)行任何的格式化處理,比較合適存儲(chǔ)一些簡(jiǎn)單的文本數(shù)據(jù)或二進(jìn)制數(shù)據(jù)
- SharedPreferences
使用鍵值對(duì)的方式來(lái)存儲(chǔ)數(shù)據(jù),保存數(shù)據(jù)更加方便。數(shù)據(jù)以明文的方式保存在文件中,需要加密,一般保存應(yīng)用設(shè)置。
- SQLite 繼承SqLiteOpenHelper類創(chuàng)建數(shù)據(jù)庫(kù),
可以保存大量復(fù)雜的關(guān)系型數(shù)據(jù)?
賬號(hào)密碼自動(dòng)登陸:
在項(xiàng)目中,我們一般使用SharePrefences實(shí)現(xiàn)自動(dòng)登錄的功能,在登錄成功后,將數(shù)據(jù)(用戶名,密碼)保存在SharePrefences中,然后再次進(jìn)入app時(shí),判斷SharePrefences中有無(wú)數(shù)據(jù),有的話就跳到主頁(yè)面,沒(méi)有的話就跳到登錄頁(yè)。
SharedPreferences 的源碼實(shí)現(xiàn):
SharedPreferences 是線程安全的。
final class SharedPreferencesImpl implements SharedPreferences {// 1、使用注釋標(biāo)記鎖的順序// Lock ordering rules:// - acquire SharedPreferencesImpl.mLock before EditorImpl.mLock// - acquire mWritingToDiskLock before EditorImpl.mLock// 2、通過(guò)注解標(biāo)記持有的是哪把鎖@GuardedBy("mLock")private Map<String, Object> mMap;@GuardedBy("mWritingToDiskLock")private long mDiskStateGeneration;public final class EditorImpl implements Editor {@GuardedBy("mEditorLock")private final Map<String, Object> mModified = new HashMap<>();} }SharedPreferences 是由 Context 返回的,獲取 SharedPreferences 的方法定義在抽象類 Context 中。
public abstract SharedPreferences getSharedPreferences(String name, int mode);public abstract SharedPreferences getSharedPreferences(File file, int mode);第一個(gè)方法是我們常用的,只要傳入文件名,SP會(huì)自動(dòng)尋找已有文件或創(chuàng)建,第二個(gè)是我們傳入的文件。
所以 SharedPreferences 的操作,本質(zhì)上就是對(duì)文件的操作,使用SharedPreferences時(shí),只有第一次讀取數(shù)據(jù)是有概率卡主線程幾十到幾百毫秒,而之后的讀取時(shí)間幾乎可以忽略不計(jì)。最后會(huì)落實(shí)到一個(gè) xml 文件上。
@Overridepublic File getSharedPreferencesPath(String name) {return makeFilename(getPreferencesDir(), name + ".xml");}標(biāo)準(zhǔn)路徑在 /data/data/應(yīng)用包名/shared_prefs 文件夾中,且都是 xml 文件。
commit 和 apply 的對(duì)比
EditorImpl 內(nèi)部有一個(gè)內(nèi)存緩存,用來(lái)保存用戶修改后的操作:
private final Map<String, Object> mModified = Maps.newHashMap();在執(zhí)行 commit 或者 apply 前,比如editor.putString("Key","Value")會(huì)把修改存儲(chǔ)在 mModified 中。
public Editor putString(String key, @Nullable String value) {synchronized (this) {mModified.put(key, value);return this;}}}commit(同步):構(gòu)造一個(gè)MemoryCommitResult來(lái)進(jìn)行結(jié)果投遞,在post任務(wù)以后會(huì)直接在當(dāng)前線程進(jìn)行wait。
apply(異步):構(gòu)造一個(gè)MemoryCommitResult來(lái)調(diào)度IO(QueuedWork提供了singleThreadExecutor),apply()不會(huì)等待,而由QueuedWork的waitToFinish()方法的調(diào)用者(ActivityThread)來(lái)保證在某些時(shí)間點(diǎn)等待task的完成。
QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);QueuedWork:一個(gè)內(nèi)部工具類,用于跟蹤那些未完成的或尚未結(jié)束的全局任務(wù)。由?waitToFinish?方法保證執(zhí)行,在?Activity onStop 以及 Service 處理 onStop,onStartCommand 時(shí)等待寫(xiě)入操作,所有排隊(duì)的異步任務(wù)都在一個(gè)獨(dú)立、專用的線程上處理。平時(shí)使用的時(shí)候,盡量使用 apply 避免卡住主線程。
apply方法造成的ANR:
在apply()方法中,首先會(huì)創(chuàng)建一個(gè)等待鎖,最終更新文件的任務(wù)會(huì)交給QueuedWork.singleThreadExecutor()單個(gè)線程或者HandlerThread去執(zhí)行,當(dāng)文件更新完畢后會(huì)釋放鎖。 但當(dāng)Activity.onStop()以及Service處理onStop等相關(guān)方法時(shí),則會(huì)執(zhí)行 QueuedWork.waitToFinish()等待所有的等待鎖釋放,因此如果SharedPreferences一直沒(méi)有完成更新任務(wù),有可能會(huì)導(dǎo)致卡在主線程,最終超時(shí)導(dǎo)致ANR。
加載 xml 數(shù)據(jù)文件
?SharedPreferences 的加載流程,就是把文件的內(nèi)容載入內(nèi)存的過(guò)程。
private void loadFromDisk() {...str = new BufferedInputStream(new FileInputStream(mFile), 16*1024);map = XmlUtils.readMapXml(str);...}本質(zhì)上,就是讀取一個(gè) xml 文件,被內(nèi)容解析為 Map 對(duì)象。這個(gè) map 包含了我們之前保存的所有鍵值對(duì)的數(shù)據(jù)。?
SharedPreferences 的讀取非???#xff0c;載入完成后,后面的讀操作都是針對(duì) mMap 的,響應(yīng)速度是內(nèi)存級(jí)別的非???。
SharedPreferences 不存放大量數(shù)據(jù)原因:
- apply操作耗時(shí)過(guò)久會(huì)導(dǎo)致ANR
- 如果數(shù)據(jù)量很大的話,返回的map對(duì)象會(huì)占很大一塊內(nèi)存
總結(jié)
以上是生活随笔為你收集整理的Android—数据持久化、SP源码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《C++字符串完全指南——第一部分:wi
- 下一篇: Android—Broadcast原理