http://www.mysamplecode.com/2011/11/android-shared-preferences-example_12.html


http://lfhck.com/question/300853/sharedpreferencesonsharedpreferencechangelistener-not-being-called-consistently


http://www.androidadb.com/class/on/OnPreferenceChangeListener.html



http://www.sourcetricks.com/2012/07/android-preference-change-listener.html



http://stackoverflow.com/questions/2542938/sharedpreferences-onsharedpreferencechangelistener-not-being-called-consistently


I'm registering a preference change listener like this (in the onCreate() of my main activity):

SharedPreferences prefs = 
    PreferenceManager.getDefaultSharedPreferences(this);

prefs.registerOnSharedPreferenceChangeListener(
    new SharedPreferences.OnSharedPreferenceChangeListener() {
        public void onSharedPreferenceChanged(
            SharedPreferences prefs, String key) {

            System.out.println(key);
        }
    });

The trouble is, the listener is not always called. It works for the first few times a preference is changed, and then it is no longer called until I uninstall and reinstall the app. No amount of restarting the application seems to fix it.

I found a mailing list thread reporting the same problem, but no one really answered him. What am I doing wrong?


3 answers

 98.35% - Blanka Best Answer

This is a sneaky one. SharedPreferences keeps listeners in a WeakHashMap. This means that you cannot use an anonymous inner class as a listener, as it will become the target of garbage collection as soon as you leave the current scope. It will work at first, but eventually, will get garbage collected, removed from the WeakHashMap and stop working.

Keep a reference to the listener in a field of your class and you will be OK, provided your class instance is not destroyed.

i.e. instead of:

prefs.registerOnSharedPreferenceChangeListener(
  new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // Implementation
  }
});

do this:

// Use instance field for listener
// It will not be gc'd as long as this instance is kept referenced
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
  public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    // Implementation
  }
};

prefs.registerOnSharedPreferenceChangeListener(listener);

The reason unregistering in the onDestroy method fixes the problem is because to do that you had to save the listener in a field, therefore preventing the issue. It's the saving the listener in a field that fixes the problem, not the unregistering in onDestroy.

 51.01% - user1121150

As this is the most detailed page for the topic I want to add my 50ct.

I had the problem that OnSharedPreferenceChangeListener wasn't called. My SharedPreferences are retrieved at the start of the main Activity by:

prefs = PreferenceManager.getDefaultSharedPreferences(this);

My PreferenceActivity code is short and does nothing except showing the preferences:

public class Preferences extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // load the XML preferences file
        addPreferencesFromResource(R.xml.preferences);
    }
}

Every time the the menu button is pressed I create the PreferenceActivity from the main Activity:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    //start Preference activity to show preferences on screen
    startActivity(new Intent(this, Preferences.class));
    //hook into sharedPreferences. THIS NEEDS TO BE DONE AFTER CREATING THE ACTIVITY!!!
    prefs.registerOnSharedPreferenceChangeListener(this);
    return false;
}

Note that registering the OnSharedPreferenceChangeListener needs to be done AFTER creating the PreferenceActivity in this case, else the Handler in the main Activity won't be called!!! It took me some sweet time to realize that...

 34.24% - Samuel

this accepted answer is ok, as for me it is creating new instance each time the activity resumes

so how about keeping the reference to the listener within the activity

OnSharedPreferenceChangeListener myPrefListner = new OnSharedPreferenceChangeListener(){
      public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
         // your stuff
      }
};

and in your onResume and onPause

@Override     
protected void onResume() {
    super.onResume();          
    getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(myPrefListner);     
}



@Override     
protected void onPause() {         
    super.onPause();          
    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(myPrefListner);

}

this will very similar to what you are doing except we are maintaining a hard reference.


Question and answers from http://stackoverflow.com/.