SharedPreferences使用及原理
一、SharedPreferences介紹
SharedPreferences 類提供了一個通用框架,以便您能夠保存和檢索原始數(shù)據(jù)類型的永久性鍵值對。您可以使用 SharedPreferences 來保存任何原始數(shù)據(jù):布爾值,浮點值,整型值,長整型和字符串。此數(shù)據(jù)將跨多個用戶會話永久保留(即使您的應用已終止亦如此)。
SharedPreferences 使用 xml 格式為 Android 應用提供一種永久數(shù)據(jù)存貯方式,并且使用鍵值對的方式來存儲數(shù)據(jù)的。相對于一個 Android 應用而言,目錄 / data/data/your_app_package_name/shared_prefs / 下,可以被處在同一個應用中的所有 Activity 訪問。Android 提供了相關(guān)的 API 來處理這些數(shù)據(jù)而不需要程序員直接操作這些文件或者考慮數(shù)據(jù)同步的問題。
二、SharedPreferences使用
SharedPreferences 本身是一個接口,程序無法直接創(chuàng)建 SharedPreferences 的實例,只能通過 Context 提供的 getSharedPreferences(String name,int mode) 方法來獲取 SharedPreferences 的實例,其中有兩個參數(shù):第一個參數(shù)用于指定 SharedPreferences 文件的名稱(格式為 xml 文件),如果該名稱的文件不存在則會創(chuàng)建一個。第二個參數(shù)用于指定操作的模式,如下:
- MODE_PRIVATE:默認操作模式,只有本應用程序才可以對這個 SharedPreferences 文件進行讀寫。
- MODE_WORLD_READABLE:其他應用對這個 SharedPreferences 文件只能讀不能修改。
- MODE_WORLD_WRITEABLE:這個 SharedPreferences 文件能被其他的應用讀寫。
- MODE_MULTI_PROCESS:這個模式在 Android2.3 之后已經(jīng)棄之不用了,可以省略。
此外還得提一下 SharedPreferences.Editor 對象的一些主要方法。
- SharedPreferences.Editor clear(): 刪 SharedPreferences 中所有的數(shù)據(jù)。
- SharedPreferences.Editor putXxx(String key , xxx value): 向 SharedPreferences 存入指定 key 對應的數(shù)據(jù),其中 xxx 可以是 booleant 等各種基本類型數(shù)據(jù) 。
- SharedPreferences.Editor remove(): 刪除 SharedPreferences 中指定 key 對應的數(shù)據(jù)項
- boolean commit(): Editor 編輯完成后,使用該方法同步提交修改。
- void apply(): Editor 編輯完成后,使用該方法異步提交修改。
簡單理解:在鍵值對中存儲私有原始數(shù)據(jù)。
適用范圍:用于保存少量數(shù)據(jù),且數(shù)據(jù)的格式非常簡單,如應用程序的各種配置信息。常見案例:音樂開關(guān),用戶賬戶設置,用戶習慣設置,簡單拓展:判斷程序是不是第一次運行(使安卓 app 安卓后引導界面只顯示一次)。
三、SharedPreferences優(yōu)化
3.1 讀操作的優(yōu)化
每次讀取一個key對應的值都要重新對文件進行一次讀的操作?顯然需要盡量避免笨重的I/O操作。
因此設計者針對讀操作進行了簡單的優(yōu)化,當SharedPreferences對象第一次通過Context.getSharedPreferences()進行初始化時,對xml文件進行一次讀取,并將文件內(nèi)所有內(nèi)容(即所有的鍵值對)緩到內(nèi)存的一個Map中,這樣,接下來所有的讀操作,只需要從這個Map中取就可以了:
final class SharedPreferencesImpl implements SharedPreferences {private final File mFile; // 對應的xml文件private Map<String, Object> mMap; // Map中緩存了xml文件中所有的鍵值對 }雖然節(jié)省了I/O的操作,但另一個視角分析,當xml中數(shù)據(jù)量過大時,這種 內(nèi)存緩存機制 是否會產(chǎn)生 高內(nèi)存占用 的風險?
這也正是很多開發(fā)者詬病SharedPreferences的原因之一,那么,從事物的兩面性上來看,高內(nèi)存占用 真的是設計者的問題嗎?
不盡然,因為SharedPreferences的設計初衷是數(shù)據(jù)的 輕量級存儲 ,對于類似應用的簡單的配置項(比如一個boolean或者int類型),即使很多也并不會對內(nèi)存有過高的占用;而對于復雜的數(shù)據(jù)(比如復雜對象序列化后的字符串),開發(fā)者更應該使用類似Room這樣的解決方案,而非一股腦存儲到SharedPreferences中。
因此,相對于「SharedPreferences會導致內(nèi)存使用過高」的說法,更傾向于更客觀的進行總結(jié):
雖然 內(nèi)存緩存機制 表面上看起來好像是一種 空間換時間 的權(quán)衡,實際上規(guī)避了短時間內(nèi)頻繁的I/O操作對性能產(chǎn)生的影響,而通過良好的代碼規(guī)范,也能夠避免該機制可能會導致內(nèi)存占用過高的副作用,所以這種設計是 值得肯定 的。
3.2 寫操作的優(yōu)化
針對寫操作,設計者同樣設計了一系列的接口,以達到優(yōu)化性能的目的。
我們知道對鍵值對進行更新是通過mSharedPreferences.edit().putString().commit()進行操作的——edit()是什么,commit()又是什么,為什么不單純的設計初mSharedPreferences.putString()這樣的接口?
設計者希望,在復雜的業(yè)務中,有時候一次操作會導致多個鍵值對的更新,這時,與其多次更新文件,我們更傾向?qū)⑦@些更新 合并到一次寫操作 中,以達到性能的優(yōu)化。
因此,對于SharedPreferences的寫操作,設計者抽象出了一個Editor類,不管某次操作通過若干次調(diào)用putXXX()方法,更新了幾個xml中的鍵值對,只有調(diào)用了commit()方法,最終才會真正寫入文件:
// 簡單的業(yè)務,一次更新一個鍵值對 sharedPreferences.edit().putString().commit();// 復雜的業(yè)務,一次更新多個鍵值對,仍然只進行一次IO操作(文件的寫入) Editor editor = sharedPreferences.edit(); editor.putString(); editor.putBoolean().putInt(); editor.commit(); // commit()才會更新文件了解到這一點應該明白,通過簡單粗暴的封裝,以達到類似SPUtils.putXXX()這種所謂代碼量的節(jié)省,從而忽略了Editor.commit()的設計理念和使用場景,往往是不可取的,從設計上來講,這甚至是一種 倒退 。
另外一個值得思考的角度是,本質(zhì)上文件的I/O是一個非常重的操作,直接放在主線程中的commit()方法某些場景下會導致ANR(比如數(shù)據(jù)量過大),因此更合理的方式是應該將其放入子線程執(zhí)行。
因此設計者還為Editor提供了一個apply()方法,用于異步執(zhí)行文件數(shù)據(jù)的同步,并推薦開發(fā)者使用apply()而非commit()。
看起來Editor+apply()方法對寫操作做了很大的優(yōu)化,但更多的問題隨之而來,比如子線程更新文件,必然會引發(fā) 線程安全問題;此外,apply()方法真的能夠像我們預期的一樣,能夠避免ANR嗎?答案是并不能。
總結(jié)
以上是生活随笔為你收集整理的SharedPreferences使用及原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux文件操作
- 下一篇: 如何通过VB合并Excel单元格以及设置