我正在注册一个这样的首选项更改侦听器(在我的主活动的onCreate()中):
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(
SharedPreferences prefs, String key) {
System.out.println(key);
}
});
问题是,侦听器并不总是被调用。在首选项改变的前几次,它是有效的,然后它不再被调用,直到我卸载并重新安装应用程序。重新启动应用程序似乎无法修复它。
我发现一个邮件列表线程报告了同样的问题,但没有人真正回答他。我做错了什么?
Kotlin代码,用于注册SharedPreferenceChangeListener,它检测何时将发生在保存的键上的变化:
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener { sharedPreferences, key ->
if(key=="language") {
//Do Something
}
}
你可以把这个代码放在onStart(),或其他地方..
*考虑你必须使用
if(key=="YourKey")
或者你的代码在“//Do Something”块将错误地运行每一个变化,将发生在任何其他键在sharedPreferences
每次调用onResume时,接受的答案都会创建一个SharedPreferenceChangeListener。@Samuel通过将SharedPreferenceListener作为Activity类的成员来解决这个问题。但是谷歌在这个代码实验室中也使用了第三种更直接的解决方案。让你的活动类实现OnSharedPreferenceChangeListener接口,并在活动中覆盖onSharedPreferenceChanged,有效地使活动本身成为一个SharedPreferenceListener。
public class MainActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
}
@Override
protected void onStart() {
super.onStart();
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onStop() {
super.onStop();
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(this);
}
}
由于这是主题最详细的页面,我想添加我的50ct。
我有一个问题,OnSharedPreferenceChangeListener没有被调用。我的SharedPreferences在主活动的开始被检索:
prefs = PreferenceManager.getDefaultSharedPreferences(this);
My PreferenceActivity代码很短,除了显示首选项外什么都不做:
public class Preferences extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// load the XML preferences file
addPreferencesFromResource(R.xml.preferences);
}
}
每次按下菜单按钮,我都会从主Activity中创建PreferenceActivity:
@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;
}
注意,在这种情况下,注册OnSharedPreferenceChangeListener需要在创建PreferenceActivity之后完成,否则主活动中的处理程序将不会被调用!!我花了很长时间才意识到……
监听器保存在WeakHashMap中是有意义的。因为大多数时候,开发人员更喜欢这样编写代码。
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(
new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
Log.i(LOGTAG, "testOnSharedPreferenceChangedWrong key =" + key);
}
});
这似乎并不坏。但是如果onsharedpreferencechangelistener的容器不是WeakHashMap,那就很糟糕了。如果上面的代码是在活动中编写的。由于您使用的是非静态(匿名)内部类,它将隐式地保存封闭实例的引用。这将导致内存泄漏。
更重要的是,如果你保持监听器作为一个字段,你可以在开始时使用registerOnSharedPreferenceChangeListener,并在结束时调用unregisterOnSharedPreferenceChangeListener。但是您不能在方法的作用域之外访问局部变量。所以你只有注册的机会,没有取消注册的机会。因此,使用WeakHashMap将解决这个问题。这是我推荐的方法。
如果将侦听器实例设置为静态字段,则可以避免非静态内部类造成的内存泄漏。但是由于侦听器可以是多个,所以它应该是与实例相关的。这将减少处理onSharedPreferenceChanged回调的成本。