在偏好檔案中儲存資料,偏好檔案儲存體資料
SharedPreferences對象使用常規的XML檔案來儲存資料,這些檔案儲存體在應用程式的資料目錄內。該XML檔案的結構很簡單,因為它只允許儲存鍵/值對,不過Android API還提供了非常方便的抽象,允許開發人員以型別安全的方式讀寫資料。
建立SharedPreferences對象最簡單的方式是使用PreferenceManager.getDefaultSharedPreferences()方法,它會返回應用程式預設的偏好對象。使用該方式來儲存主要的喜好設定很方便,因為架構會自動管理好檔案名稱。但是,如果應用程式有多個偏好檔案,最好使用Context.getSharedPreference()方法,它允許開發人員自由地命名檔案。如果只是建立和Activity相關的偏好檔案,可以使用Activity.getPreference()方法,它會在調用時得到Activity的名字。
PreferenceManager.getDefaultSharedPreferences()建立的偏好檔案名稱是由包名以及尾碼_preferences組成的,如com.liyuanjinglyj.code_preferences。雖然很少需要這個名字,但如果要實現檔案備份代理該名字就很重要。
SharedPreferences支援的儲存值的類型有int,float.long.boolean,String以及set<String>對象。鍵名必須是一個有效字串,常見的做法是使用點符號按組結構化多個鍵值。
例如,如果偏好檔案包含用於網路設定以及使用者介面設定相關的值,可以通過為每個鍵添加network或者ui首碼來把它們分組。通過該方式,開發人員可以輕鬆的管理鍵/值對,避免命名衝突。下面的例子示範了如何通過使用首碼並在單獨的Java介面檔案中定義鍵來結構化偏好資料:
public interface Constants { public static final String NETWORK_PREFIX = "network."; public static final String UI_PREFIX = "ui."; public static final String NETWORK_RETRY_COUNT = NETWORK_PREFIX + "retryCount"; public static final String NETWORK_CONNECTION_TIMEOUT = NETWORK_PREFIX + "connectionTimeout"; public static final String NETWORK_WIFI_ONLY = NETWORK_PREFIX + "wifiOnly"; public static final String UI_BACKGROUND_COLOR = UI_PREFIX + "backgroundColor"; public static final String UI_FOREGROUND_COLOR = UI_PREFIX + "foregroundColor"; public static final String UI_SORT_ORDER = UI_PREFIX + "sortOrder"; public static final int SORT_ORDER_NAME = 10; public static final int SORT_ORDER_AGE = 20; public static final int SORT_ORDER_CITY = 30;}
推薦使用上面的方法訪問儲存的偏好值,而不是把鍵名寫入程式碼在代碼中。這樣做可以避免誤拼字,從而減少由於拼字導致的bug。
下面的代碼示範了使用之前定義的Constants類來訪問偏好檔案:
private void readUiPreferences() { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); int defaultBackgroundColor = getResources(). getColor(R.color.default_background); int backgroundColor = preferences.getInt( Constants.UI_BACKGROUND_COLOR, defaultBackgroundColor); View view = findViewById(R.id.background_view); view.setBackgroundColor(backgroundColor);}
要修改儲存在偏好檔案中的值,首先需要擷取Editor執行個體,它提供了相應的PUT方法,以及用於提交修改的方法。在Android2.3之前,通過使用commit()方法把修改同步提交到存放裝置中。但在2.3版本中,Editor提供了用於非同步執行寫操作的apply()方法。因為要儘可能地避免在主線程執行阻塞的操縱,apply()方法比之前的commit()方法更好。這使得在主線程直接從UI操作更新SharedPreferences很安全。
public void doToggleWifiOnlyPreference(View view) { SharedPreferences preferences = PreferenceManager. getDefaultSharedPreferences(this); boolean currentValue = preferences. getBoolean(Constants.NETWORK_WIFI_ONLY, false); preferences.edit() .putBoolean(Constants.NETWORK_WIFI_ONLY, !currentValue) .apply();}
上面的代碼顯示了使用點擊監聽器來切換儲存在Constants.NETWORK_WIFI_ONLY中的偏好值。如果使用之前的commit()方法,主線程可能會被阻塞,導致使用者體驗差。使用apply()方法就不需要擔心上面的問題。
在同一個進程中,每個偏好檔案都只有執行個體。所以即便從二個不同的組件使用相同的名字擷取二個SharedPreference對象,它實際上還是共用同一個執行個體,所以對於一個對象的改變會立即影響到另一個對象。
為了能在偏好值被修改的時候收到通知,開發人員需要註冊一個監聽器回呼函數,每當調用apply()或者commit()方法時都會觸發該監聽器回呼函數。最常見的例子是,在Activity中修改偏好值應該影響後台Service的行為,如下所示:
public class NetworkService extends IntentService implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String TAG = "NetworkService"; private boolean mWifiOnly; public NetworkService() { super(TAG); } @Override public void onCreate() { super.onCreate(); SharedPreferences preferences = PreferenceManager .getDefaultSharedPreferences(this); preferences.registerOnSharedPreferenceChangeListener(this); mWifiOnly = preferences.getBoolean(Constants.NETWORK_WIFI_ONLY, false); } @Override protected void onHandleIntent(Intent intent) { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); int type = networkInfo.getType(); if (mWifiOnly && type != ConnectivityManager.TYPE_WIFI) { Log.d(TAG, "只執行WIFI網路"); return; } performNetworkOperation(intent); } @Override public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { if (Constants.NETWORK_WIFI_ONLY.equals(key)) { mWifiOnly = preferences .getBoolean(Constants.NETWORK_WIFI_ONLY, false); if(mWifiOnly) { cancelNetworkOperationIfNecessary(); } } } @Override public void onDestroy() { super.onDestroy(); SharedPreferences preferences = PreferenceManager .getDefaultSharedPreferences(this); preferences.unregisterOnSharedPreferenceChangeListener(this); } private void cancelNetworkOperationIfNecessary() { // 取消網路操作。 } private void performNetworkOperation(Intent intent) { // 連上網路操作 }}