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