onSharedPreferenceChanged не запускается, если изменение происходит в отдельном действии?
Я реализовал onSharedPreferenceChanged
в моей основной деятельности.
Если я изменяю настройки в основном действии, мое событие запускается.
Если я изменю настройки через экран настроек (PreferenceActivity
) мое событие НЕ запускается при изменении настроек (потому что это отдельное действие и отдельная ссылка на sharedPreferences?)
Кто-нибудь есть рекомендации о том, как мне идти о преодолении этой ситуации?
Спасибо!
EDIT1: я пытался добавить обработчик событий прямо в мои предпочтения деятельности, но он никогда не срабатывает. Следующий метод вызывается во время 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 ответов
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 не вызывается последовательно
Это произошло потому, что сборщик мусора. его работы только один раз. тогда ссылка собирается как мусор. поэтому создайте поле экземпляра для слушателя.
private OnSharedPreferenceChangeListener listner;
listner = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
//implementation goes here
}
};
prefs.registerOnSharedPreferenceChangeListener(listner);
Я прибыл сюда, как и многие другие, потому что мой слушатель не будет уволен, когда я сменил свой логический true
в false
, или наоборот.
После большого чтения и рефакторинга, переключение contexts/inner
classes/privates/static/
и тому подобное, я понял свою (глупую) ошибку:
onSharedPreferenceChanged
вызывается только если что-то меняется. Только. Когда-либо.
Во время моих тестов я был настолько глуп, чтобы постоянно нажимать на одну и ту же кнопку, поэтому все время присваивал предпочтение одному и тому же логическому значению, поэтому оно никогда не менялось.
Надеюсь, это кому-нибудь поможет!!
Еще один способ избежать этой проблемы - сделать вашу деятельность классом слушателя. Поскольку существует только один метод переопределения с отличительным именем, вы можете сделать это:
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)
{
...
}
}
Обратите внимание, что в первоначальном вопросе говорилось о MainActivity, слушающей изменения настроек в PreferenceActivity. Затем он добавил "EDIT1" и изменил вопрос на прослушивание в самой PreferenceActivity. Это проще, чем первый, и, кажется, это то, что предполагают все ответы. Но что, если вы все еще хотите прежний сценарий?
Ну, это тоже будет работать, но не используйте OnResume() и OnPause() для регистрации и отмены регистрации слушателя. Это приведет к тому, что слушатель окажется неэффективным, потому что пользователь покидает MainActivity, когда использует PreferenceActivity (что имеет смысл, когда вы об этом думаете). Так что это будет работать, но тогда ваша MainActivity будет по-прежнему слушать в фоновом режиме, даже если пользователь не использует его. Вид пустой траты ресурсов не так ли? Таким образом, есть другое решение, которое, кажется, работает: просто добавьте метод в OnResume(), чтобы перечитать все настройки. Таким образом, когда пользователь заканчивает редактирование предпочтений в PreferenceActivity, MainActivity выбирает их, когда пользователь возвращается к нему, и вам вообще не нужен слушатель.
Кто-то, пожалуйста, дайте мне знать, если они видят проблему с этим подходом.
Сборщик мусора стирает это... вы должны рассмотреть вместо этого использование контекста приложения... или просто добавить код при запуске приложения... и затем добавить прослушиватель с контекстом приложения...
Подумайте о том, чтобы сохранить PreferencesChangeListener внутри экземпляра класса Android App. Хотя это НЕ чистое решение для хранения ссылок внутри приложения, оно должно остановить сборщик мусора 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
}
}
}
Почему бы вам просто не добавить onSharedPreferenceChanged
в остальной части деятельности, где предпочтения могут измениться?
При чтении удобочитаемых данных Word, передаваемых первым приложением, мы должны
замещать
getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);
с
getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);
во втором приложении, чтобы получить обновленное значение во втором приложении.