Я регистрирую предпочтительного слушателя изменения как это (в onCreate()
из моего основного вида деятельности):
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(
SharedPreferences prefs, String key) {
System.out.println(key);
}
});
Проблема, слушателя не всегда звонят. Это работает на первые несколько раз предпочтение, изменяется, и затем это больше не называют, пока я не удаляю и переустанавливаю приложение. Никакой объем перезапуска приложения, кажется, не фиксирует его.
Я нашел поток списка рассылки, сообщающий о той же проблеме, но никто действительно не ответил ему. Что я делаю неправильно?
Это коварно. 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 referenced
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
// Implementation
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
Причина, по которой отмена регистрации в методе onDestroy устраняет проблему, заключается в том, что для этого вам пришлось сохранить слушателя в поле, тем самым предотвратив проблему. Именно сохранение слушателя в поле устраняет проблему, а не снятие регистрации в onDestroy.
UPDATE: Документация по Android была обновлена с предупреждениями об этом поведении. Итак, странное поведение остается. Но теперь оно задокументировано.