How to listen for preference changes within a PreferenceFragment?
As described here, I am subclassing PreferenceFragment and displaying it inside an Activity. That document explains how to listen for preference changes here, but only if you subclass PreferenceActivity. Since I'm not doing that, how do I listen for preference changes?
I've tried implementing OnSharedPreferenceChangeListener in my PreferenceFragment but it does not seem to work (onSharedPreferenceChanged
never seems to get called).
This is my code so far:
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
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:defaultValue="15"
android:enabled="true"
android:key="pref_number_of_exercises"
android:numeric="integer"
android:title="Number of exercises" />
</PreferenceScreen>
Also, is the PreferenceFragment even the right place to listen for preference changes or should I do it within the Activity?
Solution 1:
I believe you just need to register/unregister the Listener
in your PreferenceFragment
and it will work.
@Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
Depending on what you want to do you may not need to use a listener. Changes to the preferences are committed to SharedPreferences
automatically.
Solution 2:
The solution of antew works well, here you can see a full preference activity for Android v11 onwards:
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");
}
}
}
Solution 3:
All the other answers are correct. But I like this alternative better because you immediately have the Preference instance that caused the change.
@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;
}
});
}
Solution 4:
This worked for me from PreferenceFragment.onCreate()
OnSharedPreferenceChangeListener listener =
new SharedPreferences.OnSharedPreferenceChangeListener()
{
public void onSharedPreferenceChanged(SharedPreferences prefs, String key)
{
showDialog();
}
};