为了账号安全,请及时绑定邮箱和手机立即绑定

不一致地调用SharedPreferences.onSharedPreference

不一致地调用SharedPreferences.onSharedPreference

青春有我 2019-07-02 15:35:42
不一致地调用SharedPreferences.onSharedPreferenceChangeListener我正在注册一个像这样的首选项更改监听器(在onCreate()我的主要活动):SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);prefs.registerOnSharedPreferenceChangeListener(    new SharedPreferences.OnSharedPreferenceChangeListener() {        public void onSharedPreferenceChanged(          SharedPreferences prefs, String key) {          System.out.println(key);        }});问题是,听者并不总是被调用。它工作在最初的几次首选项被改变,然后它不再被调用,直到我卸载和重新安装应用程序。再多的重新启动应用程序似乎都无法修复它。我找到了一份邮件列表螺纹报告同样的问题,但没有人真正回答他。我做错什么了?
查看完整描述

3 回答

?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

这是个鬼鬼祟祟的。SharedPreferences将侦听器保存在WeakHashMap中。这意味着您不能使用匿名内部类作为侦听器,因为一旦离开当前作用域,它将成为垃圾回收的目标。它一开始可以工作,但最终会被垃圾收集、从WeakHashMap中删除并停止工作。

在类的字段中保持对侦听器的引用,只要类实例未被销毁,您就会没事。

即:而不是:

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

这样做:

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

在onDesty方法中注销的原因是修复了这个问题,因为要做到这一点,就必须在字段中保存侦听器,从而防止问题的发生。解决问题的是在字段中保存侦听器,而不是在onDesty中取消注册。

更新:Android的文档更新带着警告关于这种行为。所以,古怪的行为依然存在。但现在它被记录在案了。


查看完整回答
反对 回复 2019-07-02
?
守着星空守着你

TA贡献1799条经验 获得超8个赞

因为这是这个主题最详细的页面,所以我想添加我的50 ct。

我遇到的问题是OnSharedPreferenceChangeListener没有被调用。我的SharedPreferences是在主活动开始时通过以下方式检索的:

prefs = PreferenceManager.getDefaultSharedPreferences(this);

我的PreferenceActivity代码很短,除了显示首选项之外,什么也不做:

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

每次按下菜单按钮,我就从主活动创建PreferenceActivity:

@Overridepublic 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;}

在本例中,注册OnSharedPreferenceChangeListener需要在创建PreferenceActivity之后完成,否则将不会调用主活动中的Handler!我花了些时间才意识到.。


查看完整回答
反对 回复 2019-07-02
?
慕后森

TA贡献1802条经验 获得超5个赞

这个被接受的答案是可以接受的,对我来说,它正在创造新实例每次活动恢复时

那么,在活动中保持对侦听器的引用如何?

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

在你的时空里

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

这将非常类似于你正在做的事情,除非我们保持一个硬引用。


查看完整回答
反对 回复 2019-07-02
  • 3 回答
  • 0 关注
  • 537 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信