Saturday, January 25, 2014

Synchronizing PreferenceScreen with SharedPreferences

PrefrenceFragment.addPreferencesFromResource() loads UI from a resource file and binds UI elements with SharedPreferences values from PreferenceManager.getDefaultSharedPreferences().
Suppose our screen has a CheckBoxPreference synchronized with a boolean value in SharedPreferences. And while we are displaying the preference screen, some service modifies the boolean value in SharedPreferences (of course by posting to UI thread for access serialization).  When this happens, the screen is not refreshed automatically and continues displaying the old value.
To keep the screen synchronized with SharedPreferences, we do the following:
  1. In OurSettingsFragment.onCreate() we add a listener to the shared preferences:
    PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(listener)
  2. In OurSettingsFragment.onDestroy(), we remove the listener:
    PreferenceManager.getDefaultSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(listener)
  3. In listener's onSharedPreferenceChanged(SharedPreferences prefs, String key) method: if the key parameter is the one that was assigned to our CheckBoxPreference in XML resource file
    • Find the preference by key:
      pref = (CheckBoxPreference)getPreferenceScreen().findPreference(key)
    • Compare the value stored in pref with the value stored in SharedPreferences and modify the pref variable if the values are different:
      final boolean prefValue = prefs.getBoolean(key, defaultValue);
      if(pref.IsChecked() != prefValue) {
          pref.setChecked(prefValue);
      }
      
When we modify the value displayed by CheckBoxPreference (or other preference UI element), the state of UI element on the screen changes and the value, that the UI element displays, is stored to the underlying SharedPreferences. But since the value being stored to SharedPreferences is the same as the value that was stored by our service, our listener is not called recursively and a possible infinite loop is avoided.  Other listeners that are listening property change events also do not get notified.

No comments:

Post a Comment