onSharedPreferenceChanged не сработал, если изменение происходит в отдельном действии? - PullRequest
68 голосов
/ 26 сентября 2010

Я реализовал onSharedPreferenceChanged в своей основной деятельности.

Если я изменяю настройки в основной деятельности, мое событие запускается.

Если я изменю настройки через экран настроек (PreferenceActivity), мое событие НЕ запускается при изменении настроек (потому что это отдельное действие и отдельная ссылка на sharedPreferences?)

У кого-нибудь есть рекомендации, как мне поступить, чтобы преодолеть эту ситуацию?

Спасибо!

РЕДАКТИРОВАТЬ1: я пытался добавить обработчик событий прямо в мои предпочтения деятельности, но он никогда не срабатывает. Следующий метод вызывается во время onCreate моей предпочтительной деятельности. Когда я изменяю значения, он никогда не печатает сообщение (msg() - это оболочка для Log.d).

private void registerChangeListener () {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);

    sp.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener () {
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            msg (" ***** Shared Preference Update ***** ");
            Intent i = new Intent();
            i.putExtra("KEY", key);
            i.setAction("com.gtosoft.dash.settingschanged");

            sendBroadcast(i);

            // TODO: fire off the event
        }
    });
}

Ответы [ 9 ]

134 голосов
/ 27 сентября 2010

OnSharedPreferenceChangeListener получает мусор в вашем случае, если вы используете анонимный класс.

Чтобы решить эту проблему, используйте следующий код в PreferenceActivity для регистрации и отмены регистрации прослушивателя изменений:

public class MyActivity extends PreferenceActivity implements
    OnSharedPreferenceChangeListener {

@Override
protected void onResume() {
    super.onResume();
    // Set up a listener whenever a key changes
    getPreferenceScreen().getSharedPreferences()
            .registerOnSharedPreferenceChangeListener(this);
}

@Override
protected void onPause() {
    super.onPause();
    // Unregister the listener whenever a key changes
    getPreferenceScreen().getSharedPreferences()
            .unregisterOnSharedPreferenceChangeListener(this);
}

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,String key) 
{
  // do stuff
}

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

см. Также SharedPreferences.onSharedPreferenceChangeListener не вызывается последовательно

14 голосов
/ 05 сентября 2012

Это произошло потому, что сборщик мусора.его работы только один раз.тогда ссылка собирается как мусор.поэтому создайте поле экземпляра для слушателя.

private OnSharedPreferenceChangeListener listner;

listner = new SharedPreferences.OnSharedPreferenceChangeListener() {        
        @Override
        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
            //implementation goes here
        }
    };
    prefs.registerOnSharedPreferenceChangeListener(listner);
6 голосов
/ 10 октября 2013

Я прибыл сюда, как и многие другие, потому что мой слушатель не будет запущен, когда я поменяю логическое значение с true на false или наоборот.

После большого чтения и рефакторинга, переключенияcontexts/inner classes/privates/static/ и тому подобное, я понял свою (глупую) ошибку:

onSharedPreferenceChanged вызывается только , если что-то меняется.Только.Когда-либо.

Во время моих тестов я был настолько глуп, чтобы постоянно нажимать на одну и ту же кнопку, тем самым постоянно присваивая предпочтение одному и тому же логическому значению, поэтому оно никогда не менялось.

Надеюсь, это кому-нибудь поможет !!

3 голосов
/ 19 июля 2015

Еще один способ избежать этой проблемы - сделать вашу деятельность классом слушателя. Поскольку существует только один метод переопределения с отличительным именем, вы можете сделать это:

public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sharedPreferences.registerOnSharedPreferenceChangeListener(this);
        ...
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
    {
        ...
    }
} 
1 голос
/ 15 июля 2016

Обратите внимание, что в исходном вопросе говорилось о MainActivity, слушающей изменения настроек в PreferenceActivity. Затем он добавил «EDIT1» и изменил вопрос на прослушивание в самой PreferenceActivity. Это проще, чем первое, и кажется, что все ответы предполагают. Но что, если вы все еще хотите прежний сценарий?

Ну, это тоже будет работать, но не используйте OnResume () и OnPause () для регистрации и отмены регистрации слушателя. Это приведет к тому, что слушатель окажется неэффективным, потому что пользователь покидает MainActivity, когда использует PreferenceActivity (что имеет смысл, когда вы об этом думаете). Так что это будет работать, но тогда ваша MainActivity все равно будет прослушивать в фоновом режиме, даже если пользователь ее не использует. Вид пустой траты ресурсов не так ли? Таким образом, есть другое решение, которое, кажется, работает, просто добавьте метод в OnResume (), чтобы перечитать все настройки. Таким образом, когда пользователь заканчивает редактирование предпочтений в PreferenceActivity, MainActivity забирает их, когда пользователь возвращается к нему, и вам совсем не нужен прослушиватель .

Кто-то, пожалуйста, дайте мне знать, если они видят проблему с этим подходом.

0 голосов
/ 11 января 2019

Рассмотрим сохранение PreferencesChangeListener внутри Android Приложение Экземпляр класса. Хотя это НЕ чистое решение для хранения ссылок внутри приложения, оно должно остановить сборщик мусора GC, и вы все равно сможете получать обновления изменений БД. Помните, что менеджер предпочтений не хранит сильную ссылку на слушателя! ( WeakHashMap )

/**
 * Main application class
 */
class MyApp : Application(), KoinComponent {

    var preferenceManager: SharedPreferences? = null
    var prefChangeListener: MySharedPrefChangeListener? = null

    override fun onCreate() {
        super.onCreate()

        preferenceManager = PreferenceManager.getDefaultSharedPreferences(this)
        prefChangeListener = MySharedPrefChangeListener()
        preferenceManager?.registerOnSharedPreferenceChangeListener(prefChangeListener)
    }
}

и

class MySharedPrefChangeListener : SharedPreferences.OnSharedPreferenceChangeListener {

    /**
     * Called when a shared preference is changed, added, or removed.
     */
    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
        if (sharedPreferences == null)
            return

        if (sharedPreferences.contains(key)) {
            // action to perform
        }
    }
}
0 голосов
/ 14 ноября 2016

Сборщик мусора стирает, что ... вы должны рассмотреть вместо этого использование контекста приложения ... или просто добавить код при запуске приложения ... и затем добавить прослушиватель с контекстом приложения ...

0 голосов
/ 11 февраля 2013

При чтении читаемых данных Word, передаваемых первому приложению, мы должны

заменить

getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);

на

getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);

во втором приложении, чтобы получить обновленное значение в секундуприложение.

0 голосов
/ 26 сентября 2010

Почему бы вам просто не добавить onSharedPreferenceChanged в остальные действия, где предпочтения могут измениться?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...