SharedPreferences.onSharedPreferenceChangeListener, не называясь последовательно

Я регистрирую предпочтительного слушателя изменения как это (в onCreate() из моего основного вида деятельности):

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

prefs.registerOnSharedPreferenceChangeListener(
   new SharedPreferences.OnSharedPreferenceChangeListener() {
       public void onSharedPreferenceChanged(
         SharedPreferences prefs, String key) {

         System.out.println(key);
       }
});

Проблема, слушателя не всегда звонят. Это работает на первые несколько раз предпочтение, изменяется, и затем это больше не называют, пока я не удаляю и переустанавливаю приложение. Никакой объем перезапуска приложения, кажется, не фиксирует его.

Я нашел поток списка рассылки, сообщающий о той же проблеме, но никто действительно не ответил ему. Что я делаю неправильно?

250
задан ישו אוהב אותך 22 August 2017 в 04:26
поделиться

1 ответ

Это коварно. 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 была обновлена с предупреждениями об этом поведении. Итак, странное поведение остается. Но теперь оно задокументировано.

591
ответ дан 23 November 2019 в 02:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: