SharedPreferences.onSharedPreferenceChangeListener not being called consistently

前端 未结 8 1107
终归单人心
终归单人心 2020-11-22 06:47

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

SharedPreferences prefs = PreferenceManager.get         


        
8条回答
  •  -上瘾入骨i
    2020-11-22 07:29

    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.

    UPDATE: The Android docs have been updated with warnings about this behavior. So, oddball behavior remains. But now it's documented.

提交回复
热议问题