¿Cómo escuchar los cambios de preferencia dentro de un Fragmento de Preferencias?

Como se describe aquí , estoy subclasando PreferenceFragment y mostrándolo dentro de una Actividad. Ese documento explica cómo escuchar los cambios de preferencia aquí , pero solo si se subclasifica la actividad de preferencia. Como no estoy haciendo eso, ¿cómo escucho los cambios de preferencia?

Intenté implementar OnSharedPreferenceChangeListener en mi PreferenceFragment, pero parece que no funciona ( onSharedPreferenceChanged nunca parece ser llamado).

Este es mi código hasta ahora:

SettingsActivity.java

 public class SettingsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Display the fragment as the main content. getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); } } 

SettingsFragment.java

 public class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener { public static final String KEY_PREF_EXERCISES = "pref_number_of_exercises"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { //IT NEVER GETS IN HERE! if (key.equals(KEY_PREF_EXERCISES)) { // Set summary to be the user-description for the selected value Preference exercisesPref = findPreference(key); exercisesPref.setSummary(sharedPreferences.getString(key, "")); } } } 

preferences.xml

     

Además, ¿PreferenceFragment es el lugar correcto para escuchar los cambios de preferencias o debería hacerlo dentro de la Actividad?

Creo que solo necesita registrar / anular el registro del Listener en su PreferenceFragment y funcionará.

 @Override public void onResume() { super.onResume(); getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); super.onPause(); } 

Dependiendo de lo que quieras hacer, es posible que no necesites usar un oyente. Los cambios en las preferencias se confirman en SharedPreferences automáticamente.

La solución de antew funciona bien, aquí puedes ver una actividad de preferencia completa para Android v11 en adelante:

 import android.app.Activity; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.preference.ListPreference; import android.preference.PreferenceFragment; public class UserPreferencesV11 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Display the fragment as the main content. getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragment()).commit(); } public static class PrefsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); // set texts correctly onSharedPreferenceChanged(null, ""); } @Override public void onResume() { super.onResume(); // Set up a listener whenever a key changes getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { super.onPause(); // Set up a listener whenever a key changes getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { // just update all ListPreference lp = (ListPreference) findPreference(PREF_YOUR_KEY); lp.setSummary("dummy"); // required or will not update lp.setSummary(getString(R.string.pref_yourKey) + ": %s"); } } } 

Todas las demás respuestas son correctas. Pero me gusta más esta alternativa porque inmediatamente tienes la instancia de Preferencia que causó el cambio.

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Preference pref = findPreference(getString(R.string.key_of_pref)); pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { // do whatever you want with new value // true to update the state of the Preference with the new value // in case you want to disallow the change return false return true; } }); } 

Esto funcionó para mí desde PreferenceFragment.onCreate ()

 OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { showDialog(); } }; 

Otro ejemplo completo para que pueda ver la imagen completa.

 public class SettingsActivity extends AppCompatPreferenceActivity { /** * A preference value change listener that updates the preference's summary * to reflect its new value. */ private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object value) { String stringValue = value.toString(); if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in // the preference's 'entries' list. ListPreference listPreference = (ListPreference) preference; int index = listPreference.findIndexOfValue(stringValue); // Set the summary to reflect the new value. preference.setSummary( index >= 0 ? listPreference.getEntries()[index] : null); } else if (preference instanceof RingtonePreference) { // For ringtone preferences, look up the correct display value // using RingtoneManager. if (TextUtils.isEmpty(stringValue)) { // Empty values correspond to 'silent' (no ringtone). preference.setSummary(R.string.pref_ringtone_silent); } else { Ringtone ringtone = RingtoneManager.getRingtone( preference.getContext(), Uri.parse(stringValue)); if (ringtone == null) { // Clear the summary if there was a lookup error. preference.setSummary(null); } else { // Set the summary to reflect the new ringtone display // name. String name = ringtone.getTitle(preference.getContext()); preference.setSummary(name); } } } else { // For all other preferences, set the summary to the value's // simple string representation. preference.setSummary(stringValue); } return true; } }; /** * Helper method to determine if the device has an extra-large screen. For * example, 10" tablets are extra-large. */ private static boolean isXLargeTablet(Context context) { return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; } /** * Binds a preference's summary to its value. More specifically, when the * preference's value is changed, its summary (line of text below the * preference title) is updated to reflect the value. The summary is also * immediately updated upon calling this method. The exact display format is * dependent on the type of preference. * * @see #sBindPreferenceSummaryToValueListener */ private static void bindPreferenceSummaryToValue(Preference preference) { // Set the listener to watch for value changes. preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // Trigger the listener immediately with the preference's current value. sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager .getDefaultSharedPreferences(preference.getContext()) .getString(preference.getKey(), "")); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupActionBar(); } /** * Set up the {@link android.app.ActionBar}, if the API is available. */ private void setupActionBar() { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { // Show the Up button in the action bar. actionBar.setDisplayHomeAsUpEnabled(true); } } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { if (!super.onMenuItemSelected(featureId, item)) { NavUtils.navigateUpFromSameTask(this); } return true; } return super.onMenuItemSelected(featureId, item); } /** * {@inheritDoc} */ @Override public boolean onIsMultiPane() { return isXLargeTablet(this); } /** * {@inheritDoc} */ @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void onBuildHeaders(List
target) { loadHeadersFromResource(R.xml.pref_headers, target); } /** * This method stops fragment injection in malicious applications. * Make sure to deny any unknown fragments here. */ protected boolean isValidFragment(String fragmentName) { return PreferenceFragment.class.getName().equals(fragmentName) || GPSLocationPreferenceFragment.class.getName().equals(fragmentName) || DataSyncPreferenceFragment.class.getName().equals(fragmentName) || NotificationPreferenceFragment.class.getName().equals(fragmentName); } ////////////////// NEW PREFERENCES //////////////////////////// @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class GPSLocationPreferenceFragment extends PreferenceFragment { Preference prefGPSServerAddr, prefGPSASDID, prefIsGPSSwitch; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_gps_location); setHasOptionsMenu(true); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference("gpsServer_Addr")); bindPreferenceSummaryToValue(findPreference("gpsASD_ID")); prefGPSServerAddr = findPreference("gpsServer_Addr"); prefGPSServerAddr.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { try { // do whatever you want with new value } catch (Exception ex) { Log.e("Preferences", ex.getMessage()); } // true to update the state of the Preference with the new value // in case you want to disallow the change return false return true; } }); prefGPSASDID = findPreference("gpsASD_ID"); prefGPSASDID.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { try { // do whatever you want with new value } catch (Exception ex) { Log.e("Preferences", ex.getMessage()); } // true to update the state of the Preference with the new value // in case you want to disallow the change return false return true; } }); prefIsGPSSwitch = findPreference("isGPS_Switch"); prefIsGPSSwitch.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { try { // do whatever you want with new value } catch (Exception ex) { Log.e("Preferences", ex.getMessage()); } // true to update the state of the Preference with the new value // in case you want to disallow the change return false return true; } }); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { boolean tabletSize = getResources().getBoolean(R.bool.isTablet); if (tabletSize) { startActivity(new Intent(getActivity(), MainActivity.class)); } else { startActivity(new Intent(getActivity(), SettingsActivity.class)); } return true; } return super.onOptionsItemSelected(item); } } /////////////////////////////////////////////////////////////// /** * This fragment shows notification preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class NotificationPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_notification); setHasOptionsMenu(true); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone")); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { boolean tabletSize = getResources().getBoolean(R.bool.isTablet); if (tabletSize) { startActivity(new Intent(getActivity(), MainActivity.class)); } else { startActivity(new Intent(getActivity(), SettingsActivity.class)); } return true; } return super.onOptionsItemSelected(item); } } /** * This fragment shows data and sync preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class DataSyncPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_data_sync); setHasOptionsMenu(true); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference("sync_frequency")); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { boolean tabletSize = getResources().getBoolean(R.bool.isTablet); if (tabletSize) { startActivity(new Intent(getActivity(), MainActivity.class)); } else { startActivity(new Intent(getActivity(), SettingsActivity.class)); } return true; } return super.onOptionsItemSelected(item); } } }

Aquí hay una forma de hacerlo y evitar posibles memory leaks:

 @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.pref_movies); SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); //starts live change listener sharedPreferences.registerOnSharedPreferenceChangeListener(this); } @Override public void onDestroyView () { super.onDestroyView(); //Unregisters listener here PreferenceManager.getDefaultSharedPreferences(getContext()) .unregisterOnSharedPreferenceChangeListener(this); }