How to listen for preference changes within a PreferenceFragment?

71,392

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();
        }
    };

Solution 5

Here is one way to do it and avoid any potential 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);
}
Share:
71,392
XåpplI'-I0llwlg'I  -
Author by

XåpplI'-I0llwlg'I -

im bill grates of michaelsoft

Updated on December 19, 2020

Comments

  • XåpplI'-I0llwlg'I  -
    XåpplI'-I0llwlg'I - over 3 years

    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?

  • XåpplI'-I0llwlg'I  -
    XåpplI'-I0llwlg'I - over 11 years
    Ah, I see. That works. But should I be getting the SharedPreferences via getPreferenceManager (like you've done) or getPreferenceScreen? What's the difference?
  • antew
    antew over 11 years
    To be honest I'm not sure what the real difference is, perhaps someone else can weigh in on it, it could be a good topic for another question as well.
  • XåpplI'-I0llwlg'I  -
    XåpplI'-I0llwlg'I - over 11 years
    Okay, here is an answer to that question. It looks like there is absolutely no functional difference, but getPreferenceManager is generally the preferred option.
  • srv_sud
    srv_sud over 8 years
    when the settings-preference is created for the first time, the summary is not set as per the stored preference value. How to resolve this??
  • Jose_GD
    Jose_GD over 8 years
    @srv_sud inside your onCreate() call onSharedPreferenceChanged() directly
  • srv_sud
    srv_sud over 8 years
    @Jose_GD : what instance of pref and let to pass in that method. Because in my onShardPrefChanged() I'll process the data before updation differently for different keys.
  • Jose_GD
    Jose_GD over 8 years
    Correct, although in onSharedPreferenceChanged () you can access the Preference instance easily with findPreference(key). Maybe the SharedPreferences way is preferred because of the registering/unregistering thing?
  • Jose_GD
    Jose_GD over 8 years
    @srv_sud you mean what the key parameter should be? Haven't tried this, you have an example in Gunnar's answer below: onSharedPreferenceChanged(null, ""). It may not be suitable to your needs. Perhaps you should iterate on your keys of preferences that need an update
  • srv_sud
    srv_sud over 8 years
    @Jose_GD: ya.. i think i need to iterate .. thanks for the answer.
  • Bryan W
    Bryan W over 5 years
    In onPause, should the super.onPause() be called before or after the listener is unregistered? Is there even a difference? I've seen both in numerous examples
  • Studio2bDesigns
    Studio2bDesigns over 5 years
    @BryanWalsh I've also seen examples of both ways.. I would think unregistering the listerner before calling super.onPause(); is probably the best way to go about it.
  • pete
    pete almost 4 years
    why is unregistering necessary?
  • josef
    josef almost 4 years
    There is no this in a static class!
  • Gunnar Bernstein
    Gunnar Bernstein almost 4 years
    Can you elaborate on that? I absolutely have no clue which "this" you are referring to. The answer is 7 years old. Android has changed a lot.
  • josef
    josef over 3 years
    public static class PrefsFragment declares a static class and then uses this inside to reference itself. But that is not possible, you can not use this within a static class.
  • Gunnar Bernstein
    Gunnar Bernstein over 3 years
    Are you sure you understood the concept of static inner classes in Java? A static nested class may be instantiated without instantiating its outer class. Using 'this' is perfectly fine. This is not C#!
  • josef
    josef over 3 years
    I am not sure, but I tried the code in Android Studio and it complains on the this: " getPreferenceScreen().getSharedPreferences().registerOnShare‌​dPreferenceChangeLis‌​tener(this);". I had to rewrite the code to get it to compile.