一、簡介
在開發(fā)中,很多重要的瞬時(shí)數(shù)據(jù)都需要保存起來讓數(shù)據(jù)持久化,即 Android 中的數(shù)據(jù)持久化技術(shù)。相信這個(gè)對(duì)于大家來說并不陌生,常用的如文件存儲(chǔ)、數(shù)據(jù)庫存儲(chǔ)、SharedPreferences ,以及網(wǎng)絡(luò)存儲(chǔ)等。今天要介紹的便是其中之一的 SharedPreferences 。
SharedPreferences 是一個(gè)輕量級(jí)的存儲(chǔ)類,常用于保存軟件配置參數(shù)、賬號(hào)和密碼等。SharedPreferences 內(nèi)部使用 xml 文件將數(shù)據(jù)以 key...value 的格式保存在 “\data\data\應(yīng)用程序包名\shared_prefs\” 目錄下,在 Android Studio 中打開 Device File Explorer 即可查看。下圖是 SharedPreferences 可以保存的數(shù)據(jù)類型。

接下來是實(shí)踐時(shí)間,分別介紹利用 SharedPreferences 存數(shù)據(jù)和取數(shù)據(jù)的方法。
二、用法
(一)SharedPreferences 存數(shù)據(jù)
- 獲取 SharedPreferences 對(duì)象。Android 中提供了三種方法獲取 SharedPreferences 對(duì)象:
- Context 類中的 getSharedPreferences() 方法
/**
* Activity中直接getSharedPreferences,F(xiàn)ragment中需要getActivity().getSharedPreferences
* 參數(shù)一:SharedPreferences文件名
* 參數(shù)二:操作模式,Android6.0之后僅MODE_PRIVATE一種模式可選,表示只有當(dāng)前應(yīng)用程序才能對(duì)參數(shù)①中的文件進(jìn)行讀寫
*/
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
- Activity 類中的 getPreferences() 方法
/**
* Activity中直接getPreferences,F(xiàn)ragment中需要getActivity().getPreferences()
* 參數(shù):操作模式(此種方式獲取SharedPreferences對(duì)象時(shí)會(huì)自動(dòng)使用當(dāng)前Activity的類名作為文件名,所以只需一個(gè)參數(shù))
*/
SharedPreferences sp = getPreferences(MODE_PRIVATE);
- PreferencesManager 類中的 getDefaultSharedPreferences() 方法
/**
* PreferenceManager類的靜態(tài)方法,自動(dòng)使用當(dāng)前應(yīng)用程序包名作為前綴來命名SharedPreferences文件,操作模式自動(dòng)為MODE_PRIVATE
* 參數(shù):上下文
*/
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
- 調(diào)用 SharedPreferences 對(duì)象的 edit() 方法獲取 SharedPreferences.Editor 對(duì)象:
SharedPreferences.Editor editor = sp.edit();
- 調(diào)用 SharedPreferences.Editor 對(duì)象的 putXXX() 方法添加需要保存的數(shù)據(jù):
Set<String> userInfo = new HashSet<>();
userInfo.add("張三");
userInfo.add("20");
editor.putString("name", "張三");
editor.putBoolean("isAdult", true);
editor.putFloat("height", 178.00F);
editor.putInt("age", 20);
editor.putLong("IDNum", 123456789000L);
editor.putStringSet("user", userInfo);
- 調(diào)用 SharedPreferences.Editor 對(duì)象的 apply() 方法或者 commit() 方法提交剛剛添加的數(shù)據(jù):
//兩種提交方式都可以,任選其一即可
editor.apply();
editor.commit();
至此,利用 SharedPreferences 存儲(chǔ)數(shù)據(jù)的方法就介紹完了,下面是完整實(shí)例:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
Set<String> userInfo = new HashSet<>();
userInfo.add("張三");
userInfo.add("20");
editor.putString("name", "張三");
editor.putBoolean("isAdult", true);
editor.putFloat("height", 178.00F);
editor.putInt("age", 20);
editor.putLong("IDNum", 123456789000L);
editor.putStringSet("userInfo", userInfo);
editor.apply();
}
}
運(yùn)行程序以后,數(shù)據(jù)就已經(jīng)保存成功了,眼見為實(shí),在 Android Studio 中打開 Device File Explorer ,進(jìn)入 “\data\data\應(yīng)用程序包名\shared_prefs\” 目錄下,結(jié)果如下:

(二)SharedPreferences 取數(shù)據(jù)
- 獲取 SharedPreferences 對(duì)象。利用 SharedPreferences 存數(shù)據(jù)時(shí)已經(jīng)介紹過了獲取 SharedPreferences 對(duì)象的方法,這里不再贅述,直接看代碼:
/**
* 參數(shù)一:SharedPreferences文件名,必須和存數(shù)據(jù)時(shí)的文件名一致,存什么就取什么
* 參數(shù)二:操作模式
*/
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
- 調(diào)用 SharedPreferences 對(duì)象的 getXXX() 方法,根據(jù)存數(shù)據(jù)時(shí)約定的 key 值獲取對(duì)應(yīng)的數(shù)據(jù):
/**
* SharedPreferences對(duì)象的.getXXX()方法接收兩個(gè)參數(shù),該方法有返回值,返回key對(duì)應(yīng)的value
* 參數(shù)一:存儲(chǔ)數(shù)據(jù)時(shí)使用的key
* 參數(shù)二:默認(rèn)值,如果取值失敗則返回默認(rèn)值
*/
String name = sp.getString("name", "");
boolean isAdult = sp.getBoolean("isAdult", false);
float height = sp.getFloat("height", 0F);
int age = sp.getInt("age", 0);
long IDNum = sp.getLong("IDNum", 0L);
HashSet<String> userInfo = (HashSet<String>) sp.getStringSet("userInfo", new HashSet<String>());
至此,利用 SharedPreferences 取出數(shù)據(jù)的方法就介紹完了,下面是完整實(shí)例:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sp = getSharedPreferences("user_info", MODE_PRIVATE);
String name = sp.getString("name", "");
boolean isAdult = sp.getBoolean("isAdult", false);
float height = sp.getFloat("height", 0F);
int age = sp.getInt("age", 0);
long IDNum = sp.getLong("IDNum", 0L);
HashSet<String> userInfo = (HashSet<String>) sp.getStringSet("userInfo", new HashSet<String>());
Log.d("MyLog", "姓名:" + name);
Log.d("MyLog", "是否成年:" + isAdult);
Log.d("MyLog", "身高:" + height);
Log.d("MyLog", "年齡:" + age);
Log.d("MyLog", "身份證號(hào)碼:" + IDNum);
Log.d("MyLog", "用戶信息:" + userInfo.toString());
}
}
運(yùn)行程序后,Logcat 打印的日志結(jié)果如下:

三、apply 與 commit 的區(qū)別
- commit
/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing. This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call commit wins.
*
* <p>If you don't care about the return value and you're
* using this from your application's main thread, consider
* using {@link #apply} instead.
*
* @return Returns true if the new values were successfully written
* to persistent storage.
*/
boolean commit();
如上是 Editor.commit 方法的源碼,英文好一點(diǎn)的童鞋能從源碼注釋中了解不少東西,英語差點(diǎn)的童鞋不要著急,這里我提取出源碼注釋中的一些關(guān)鍵信息,如下:
- commit 方法用于將需要保存的數(shù)據(jù)通過 Editor 提交并保存到 SharedPreferences 對(duì)象中;
- commit 提交過程屬于原子操作,也就是該提交過程不可中斷,要么全部提交成功,要么全部提交失敗,不會(huì)出現(xiàn)只保存了其中一部分?jǐn)?shù)據(jù)的情況;
- 同一個(gè) SharedPreferences 對(duì)象,多次調(diào)用 commit 方法,最后一次的調(diào)用會(huì)覆蓋掉前面提交的數(shù)據(jù),也就是當(dāng)出現(xiàn)多次 commit 時(shí),以最后一次 commit 提交的數(shù)據(jù)為準(zhǔn);
- commit 方法有返回值( boolean 類型),意思是如果本次寫入數(shù)據(jù)成功,返回 true,否則返回 false 。
- 如果不關(guān)心返回值(不關(guān)心數(shù)據(jù)是否寫入成功),推薦使用 apply 方法提交數(shù)據(jù)。
- apply
/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing. This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call apply wins.
*
* <p>Unlike {@link #commit}, which writes its preferences out
* to persistent storage synchronously, {@link #apply}
* commits its changes to the in-memory
* {@link SharedPreferences} immediately but starts an
* asynchronous commit to disk and you won't be notified of
* any failures. If another editor on this
* {@link SharedPreferences} does a regular {@link #commit}
* while a {@link #apply} is still outstanding, the
* {@link #commit} will block until all async commits are
* completed as well as the commit itself.
*
* <p>As {@link SharedPreferences} instances are singletons within
* a process, it's safe to replace any instance of {@link #commit} with
* {@link #apply} if you were already ignoring the return value.
*
* <p>You don't need to worry about Android component
* lifecycles and their interaction with <code>apply()</code>
* writing to disk. The framework makes sure in-flight disk
* writes from <code>apply()</code> complete before switching
* states.
*
* <p class='note'>The SharedPreferences.Editor interface
* isn't expected to be implemented directly. However, if you
* previously did implement it and are now getting errors
* about missing <code>apply()</code>, you can simply call
* {@link #commit} from <code>apply()</code>.
*/
void apply();
如上是 Editor.apply 方法的源碼,這里,我照例提取出該方法的源碼注釋中的關(guān)鍵信息,如下:
- 跟 commit 方法一樣,apply 方法用于將需要保存的數(shù)據(jù)通過 Editor 提交并保存到 SharedPreferences 對(duì)象中;
- 跟 commit 方法一樣,同一個(gè) SharedPreferences 對(duì)象,多次調(diào)用 apply 方法,最后一次的調(diào)用會(huì)覆蓋掉前面提交的數(shù)據(jù),也就是當(dāng)出現(xiàn)多次 apply 時(shí),以最后一次 apply 提交的數(shù)據(jù)為準(zhǔn);