# SharedPreferences
###### tags: `android` `data persistance storage` `sharedpreferences` `key-value`
Android 提供 `SharedPreferences` 來存取簡單的 Key-Value 資料。儲存的資料型態有:`boolean`, `int`, `float`, `long`, `String`, `Set<String>`。
## 基本用法
### 取得 SharedPreference 物件
讀寫資料之前,首先由 `Context` 取得 `SharedPreferences` 物件。
取得 `SharedPreference` 需要三個參數: `Context`,`Mode`,`Key`。
#### Context
指定資料的 Scope
#### Mode
指定資料存取的權限
#### Shared Preference Key
指定哪一個 Shared Preference
#### 程式碼
```java
Context context = getActivity(); // 也可以 ApplicationContext
final String MY_SHARED_PREFERENCE_KEY = context.getString(R.string.preference_file_key);
SharedPreferences sharedPref = context.getSharedPreferences(
MY_SHARED_PREFERENCE_KEY,
Context.MODE_PRIVATE);
```
### 寫入
寫入 `SharedPreferences` 物件 必須透過 `SharedPreferences.Editor` 物件做寫入動作,寫入完成需要 `editor.commit()` 或 `editor.apply()` 才會生效。
`SharedPreferences.Editor` 支援寫入 `int`、`double`、`String`、`long`、`float`、`boolean` 及 `Set<String>` 資料型態。
#### 程式碼
```java
SharedPreferences.Editor editor = sharedPref.edit();
final String SAVED_HIGHT_SCORE_KEY = getString(R.string.saved_high_score_key);
editor.putInt(SAVED_HIGHT_SCORE_KEY, newHighScore);
... // put 其他資料
editor.commit(); // 同步提交寫入(會占用執行緒,一般不建議在主執行緒使用)
editor.apply(); // 異步提交寫入
```
### 讀取
透過 `SharedPreferences` 物件即可讀取之前儲存的值,並賦予預設值。
也可以透過 `sharedPref.getAll()` 取得所有的Key & Value。
```java
final int defaultValue = getResources().getInteger(R.integer.saved_high_score_default_value);
int highScore = sharedPref.getInt(SAVED_HIGHT_SCORE_KEY, defaultValue);
Map<String, ?> sharedPrefMap = sharedPref.getAll(); // 取得所有的 Key & Value
```
### 移除
可以移除資料
```java
sharedPref.edit()
.remove(SAVED_HIGHT_SCORE_KEY)
.commit();
```
### 設定 OnSharedPreferenceChangeListener
由於寫入可以是異步操作,我們可以透過設定 `OnSharedPreferenceChangeListener` 來監聽資料變化。
當 `SharedPreferences` 的 Key-Value 發生變化的時候,會回傳 `SharedPreferences`物件 及 Key 的值。
```java
onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
```
## 個人實踐
可以把 `SharedPreferences` 視為 一個 Table,每一筆 Key-Value 就是一筆資料
**ex:**
```java
public void storeMacNameTable(Context targetContext, List<MacNamePair> macNamePairs) {
SharedPreferences macNameTable = targetContext
.getSharedPreferences(MAC_NAME_TABLE_KEY, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = macNameTable.edit();
for(MacNamePair mnp: macNamePairs) {
editor.put(mnp.mac, mnp.name);
}
editor.apply();
}
```
## 安全性
`SharedPreferences` 將資料以 **XML格式** 儲存在 **`/data/data/PACKAGE_NAME/shared_prefs`** 目錄中。當手機被Root後就可以取得這些資料,所以敏感性的資料建議加密。可以使用Java加解密的API或 [Conceal](https://facebook.github.io/conceal/) 在資料的讀寫過程中進行加解密,也可以使用 SharedPreference 的安全封裝 [Secure-preferences](https://github.com/scottyab/secure-preferences),達到資料的加解密。
## 參考
- [Save key-value data](https://developer.android.com/training/data-storage/shared-preferences)
- [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences)