zoukankan      html  css  js  c++  java
  • OnSharedPreferenceChangeListener不被调用原理及解决方案

    问题再现

    OnSharedPreferenceChangeListener是Android中SharedPreference文件发生变化的监听器。通常我们想要进行监听,会实现如下的代码。

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

    这种写法看上去没有什么问题,而且很多时候开始几次onSharedPreferenceChanged方法也可以被调用。但是过一段时间(简单demo 不容易出现,但是使用DDMS中的gc会立刻导致接下来的问题),你会发现前面的方法突然不再被调用,进而影响到程序的处理。

    原因剖析

    简而言之,就是你注册的监听器被移除掉了。首先我们先了解一下registerOnSharedPreferenceChangeListener注册的实现。

    private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
                new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
    //some code goes here
    public void More ...registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        synchronized(this) {
          mListeners.put(listener, mContent);
        }
    }
    

    从上面的代码可以得知,一个OnSharedPreferenceChangeListener对象实际上是放到了一个WeakHashMap的容 器中,执行完示例中的onCreate方法,这个监听器对象很快就会成为垃圾回收的目标,由于放在WeakHashMap中作为key不会阻止垃圾回收, 所以当监听器对象被回收之后,这个监听器也会从mListeners中移除。所以就造成了onSharedPreferenceChanged不会被调 用。

    关于WeakHashMap相关,请阅读 译文:理解Java中的弱引用 进而更多了解。

    如何解决

    改为对象成员变量(推荐)

    将监听器作为Activity的一个成员变量,在Activity的onResume进行注册,在onPause时进行注销。推荐在这两个 Activity生命周期中进行处理,尤其是当SharedPreference值发生变化后,对Activity展示的UI进行处理操作的情况。这种方 法是最推荐的解决方案。

    private OnSharedPreferenceChangeListener mListener = new OnSharedPreferenceChangeListener() {
    
      @Override
      public void onSharedPreferenceChanged(
          SharedPreferences sharedPreferences, String key) {
          Log.i(LOGTAG, "instance variable key=" + key);
      }
    };
    
    @Override
    protected void onResume() {
      PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(mListener);
      super.onResume();
    }
    
    @Override
    protected void onPause() {
      PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).unregisterOnSharedPreferenceChangeListener(mListener);
      super.onPause();
    }
    (后略)
  • 相关阅读:
    python ascii codec can't decode
    python文件编码说明 coding=utf-8
    windbg的使用
    在后台运行Python脚本服务
    ubuntu下更改分辨率
    【转】VC调试的时候 “没有调试信息,未加载符号”
    常用正则表达式——中文匹配、拉丁匹配
    SQL的经典操作——批量复制同行的其它列数据到其它列数据
    关于C++对汉字拼音的处理(3)
    关于环境变量设置是否需要重启的问题
  • 原文地址:https://www.cnblogs.com/mgstone/p/5802384.html
Copyright © 2011-2022 走看看