Android基礎知識之SharedPreferences知識點總結

1.SharedPreferences簡介

??Sharedpreferences是Android平臺上一個輕量級的存儲類,可以用于保存應用程序的各種配置信息,如應用設置里面的各種開關、是否打開音效、是否使用震動效果、小游戲的玩家積分等,其本質是以“鍵-值”對的方式保存數據到本地的 xml 文件中,其文件保存在 /data/data/<package name>/shared_prefs 目錄下。
??核心原理:以“鍵-值”對的方式保存數據到本地的 xml 文件中,具體實現是在 SharedPreferencesImpl 里面使用Map來管理,xml 文件的具體保存路徑是在 /data/data/<package name>/shared_prefs 目錄下。SharedPreferences對象本身只能獲取數據而不支持存儲和修改,存儲修改是通過SharedPreferences.edit()獲取的內部接口Editor對象實現。

??SharedPreferences本身是一 個接口,程序無法直接創建SharedPreferences實例,只能通過Context提供的getSharedPreferences(String name, int mode)方法來獲取SharedPreferences實例,該方法中name表示要操作的xml文件名,第二個參數具體如下:

Context.MODE_APPEND: 追加方式存儲
Context.MODE_PRIVATE: 指定該SharedPreferences數據只能被本應用程序讀、寫。
Context.MODE_WORLD_READABLE:  指定該SharedPreferences數據能被其他應用程序讀,但不能寫。
Context.MODE_WORLD_WRITEABLE:  指定該SharedPreferences數據能被其他應用程序讀,寫
Context.MODE_MULTI_PROCESS: 適用于多進程訪問(目前已被廢棄,google官方推薦使用ContentProvider來實現進程間共享訪問)

Editor有如下主要重要方法:

SharedPreferences.Editor clear():清空SharedPreferences里所有數據
SharedPreferences.Editor putXxx(String key , xxx value): 向SharedPreferences存入指定key對應的數據,其中xxx 可以是boolean,float,int等各種基本類型據
SharedPreferences.Editor remove(): 刪除SharedPreferences中指定key對應的數據項
boolean commit(): 當Editor編輯完成后,使用該方法提交修改

??首次創建SharedPreferences對象(即SharedPreferences初始化時),會根據文件名將文件下內容一次性加載到mMap容器中,每當我們edit都會創建一個新的EditorImpl對象,當修改或者添加數據時會將數據添加到mModifiled容器中,然后commit或者apply操作比較mMap與mModifiled數據修正mMap中最后一次提交數據然后寫入到文件中。
??使用SharedPreferences的 get 方法獲取數據時是直接從 mMap 中讀取的,直接從 mMap 中讀取數據可以提高讀取的效率,但也間接表明 SharedPreferences 不適合存放 大的key和value,因為存放大的key和value在SharedPreferences中,數據會一直存儲在內存中得不到釋放占用較大的內存,容易引發系統 GC,嚴重時導致界面丟幀甚至ANR。

2.SharedPreferences提交數據的方法commit()、apply()的區別及使用場景

commit()、apply()的區別

  • commit() 方法是Android API 1開始就存在的方法,而 apply() 方法是從Android API 9 開始增加的方法;
  • commit() 和 apply() 雖然都是原子性操作,但是原子的操作范圍不同,commit() 是原子提交到數據庫,從提交數據到存在Disk中都是同步過程;而 apply() 方法是原子提交到內存,從內存到數據庫的更新是異步操作;
  • 提交相同的數據 commit() 方法的效率會比apply() 方法提交的速度慢,即 apply()方法提交數據的效率較高;
  • apply() 沒有返回值,而 commit() 有返回值表明提交修改是否成功。

使用場景

??從 commit()和 apply() 兩個方法的區別中可以得出兩個方法的使用場景:在一個進程中,由于sharedPreference是單實例的,只要保證內存緩存正確就能保證運行時數據的正確性,一般不會出現并發沖突,所以如果對提交結果不關心的話,建議使用apply(),只有在關心提交結果的情況下使用 commit()。

3.Sharedpreferences跨進程訪問問題

??對于多進程的應用,若在某一個進程獲取到的SP值不是最新的,很可能是創建SP的時候指定的模式有問題,應該指定為多進程的模式:Context.MODE_MULTI_PROCESS,設置之后可以實時讀取Sharedpreferences中修改后的值。

??通過Context.MODE_MULTI_PROCESS屬性使用SharedPreferences雖然可以實現多進程訪問SharedPreferences數據的問題,但是這種方式的多進程共享數據可能會出現數據不一致的問題。問題原因是因為進程間是不能內存共享的,每個進程操作的SharedPreferences都是一個單獨的實例,SharedPreferences數據寫入的時機也不確定,而且不能通過加鎖解決多進程的數據同步,從而導致了多進程間通過SharedPreferences來共享數據是不安全的。

??結論:Context.MODE_MULTI_PROCESS這個屬性Google已經廢棄,不建議使用了,對于多進程間的數據共享建議使用ContentProvider。若要用Sharedpreferences實現多進程數據共享,只能在確保不會同時操作SharedPreferences數據的前提下使用,但這個條件很難保證,所以建議最好不要使用。

4.訪問其他應用中的Preference

??如果要訪問其他應用中的Preference,必須滿足的條件是,要訪問的應用的Preference創建時指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE權限。

??舉例,假如有個<package name>為com.alexlee1987.demo下面的應用使用了下面語句創建了Preference,getSharedPreferences("demo", Context.MODE_WORLD_READABLE),現在要訪問該Preferences:

首先,需要創建上面的Context,然后通過Context訪問Preferences,訪問preference時會在應用所在包下的shared_prefs目錄找到preference:

Context context = createPackageContext("com.alexlee1987.demo", Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sharedPreferences = context.getSharedPreferences("demo", Context.MODE_WORLD_READABLE);
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 0);

??如果不通過創建Context訪問其他應用的preference,可以以讀取xml文件方式直接訪問其他應用preference對應的xml文件,如:
File xmlFile = new File(“/data/data/<package name>/shared_prefs/itcast.xml”);//<package name>應替換成應用的包名。

5.使用建議

??Sharedpreferences是Android平臺上一個輕量級的存儲類,可以方便快捷的在本地保存應用的一些信息,Sharedpreferences好用,但也不能濫用,使用過程中建議遵循以下規則:

  1. 不要存放大的key和value在SharedPreferences中,數據一直存儲在內存中得不到釋放,內存使用過高會頻發引發GC,導致界面丟幀甚至ANR;
  2. 不相關的配置選項最好不要放在一起,單個文件越大讀取速度則越慢;
  3. 讀取頻繁的key和不頻繁的key盡量不要放在一起;
  4. commit發生在UI線程中,apply發生在工作線程中,對于數據的提交最好是批量操作統一提交。雖然apply發生在工作線程(不會因為IO阻塞UI線程)但是如果添加任務較多,Activity頁面退出時有可能會阻塞,嚴重時甚至會出現ANR,具體可以參照ActivityThread源碼中handleStopActivity方法實現;


    handleStopActivity源碼
  5. 盡量不要存放json和html,這種可以直接文件緩存;
  6. 最好提前初始化SharedPreferences,避免SharedPreferences第一次創建時讀取文件線程未結束而出現等待情況,可以考慮在Application初始化的時候初始化SharedPreferences。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容