SharedPreferences.onSharedPreferenceChangeListener not being called consistently

前端 未结 8 1090
终归单人心
终归单人心 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条回答
  • 2020-11-22 07:38

    It make sense that the listeners are kept in WeakHashMap.Because most of the time, developers prefer to writing the code like this.

    PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(
        new OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(
            SharedPreferences sharedPreferences, String key) {
            Log.i(LOGTAG, "testOnSharedPreferenceChangedWrong key =" + key);
        }
    });
    

    This may seem not bad. But if the OnSharedPreferenceChangeListeners' container was not WeakHashMap, it would be very bad.If the above code was written in an Activity . Since you are using non-static (anonymous) inner class which will implicitly holds the reference of the enclosing instance. This will cause memory leak.

    What's more, If you keep the listener as a field, you could use registerOnSharedPreferenceChangeListener at the start and call unregisterOnSharedPreferenceChangeListener in the end. But you can not access a local variable in a method out of it's scope. So you just have the opportunity to register but no chance to unregister the listener. Thus using WeakHashMap will resolve the problem. This is the way I recommend.

    If you make the listener instance as a static field, It will avoid the memory leak caused by non-static inner class. But as the listeners could be multiple, It should be instance-related. This will reduce the cost of handling the onSharedPreferenceChanged callback.

    0 讨论(0)
  • 2020-11-22 07:44

    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 listener = new OnSharedPreferenceChangeListener(){
          public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
             // your stuff
          }
    };
    

    and in your onResume and onPause

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

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

    0 讨论(0)
提交回复
热议问题