onSharedPreferenceChanged no se activa si el cambio ocurre en una actividad separada?

Implementé onSharedPreferenceChanged en mi actividad principal.

Si cambio las preferencias en la actividad principal, mi evento se dispara.

Si cambio las preferencias a través de mi pantalla de preferencias ( PreferenceActivity ), mi evento NO se activa cuando cambian las preferencias (porque es una actividad separada y una referencia separada a sharedPreferences?)

¿Alguien tiene una recomendación de cómo debería hacer para superar esta situación?

¡Gracias!

EDIT1: Intenté agregar el controlador de eventos directamente en mi actividad preferida, pero nunca se dispara. Se llama al siguiente método durante onCreate de mi actividad de preferencia. Cuando cambio valores, nunca imprime el mensaje ( msg() es un contenedor para 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 } }); } 

OnSharedPreferenceChangeListener obtiene basura recolectada en su caso si usa una clase anónima.

Para resolver ese problema, use el siguiente código en PreferenceActivity para registrar y anular el registro de un detector de cambios:

 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 } 

Además, tenga en cuenta que el oyente solo recibe una llamada si el valor real cambia. Establecer el mismo valor nuevamente no disparará al oyente.

ver también SharedPreferences.onSharedPreferenceChangeListener no se llama constantemente

Esto sucede porque el recolector de basura. funciona solo una vez. entonces la referencia se recoge como basura. así que crea un campo de instancia para el oyente.

 private OnSharedPreferenceChangeListener listner; listner = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { //implementation goes here } }; prefs.registerOnSharedPreferenceChangeListener(listner); 

Llegué aquí, como muchos otros, porque mi oyente no será despedido cuando cambie mi booleano de true a false , o viceversa.

Después de leer mucho, refactorizar, cambiar contexts/inner classes/privates/static/ contexts/inner classes/privates/static/ etc., me di cuenta de mi (estúpido) error:

El onSharedPreferenceChanged solo se onSharedPreferenceChanged si algo cambia. Solamente. Nunca.

Durante mis pruebas, fui tan tonto al hacer clic en el mismo botón todo el tiempo, asignando así el mismo valor booleano a la preferencia todo el tiempo, por lo que nunca cambió.

Espero que esto ayude a alguien !!

Otra forma de evitar el problema es convertir su actividad en la clase de oyentes. Como solo hay un método de sustitución con un nombre distintivo, puede hacer esto:

 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) { ... } } 

Tenga en cuenta que la pregunta original hablaba de una actividad principal escuchando los cambios de configuración en una actividad de preferencia. El asker luego agregó un “EDIT1” y cambió la pregunta a escuchar en la actividad de preferencia en sí. Eso es más fácil que el primero y parece ser lo que asumen todas las respuestas. Pero, ¿y si aún quieres el escenario anterior?

Bueno, funcionará también, pero no use OnResume () y OnPause () para registrar y anular el registro del oyente. Hacerlo hará que el oyente sea ineficaz porque el usuario abandona la actividad principal cuando usa la actividad de preferencia (que tiene sentido cuando lo piensas). Por lo tanto, funcionará, pero su MainActivity seguirá escuchando en segundo plano incluso cuando el usuario no lo esté utilizando. Una especie de desperdicio de recursos, ¿no? Entonces, hay otra solución que parece funcionar, simplemente agregue un método a OnResume () para volver a leer todas las preferencias. De esta manera, cuando un usuario finaliza las preferencias de edición en una actividad de preferencia, MainActivity las recogerá cuando el usuario regrese a ella y no necesita un oyente en absoluto .

Alguien por favor avíseme si ven un problema con este enfoque.

¿Por qué no agrega un onSharedPreferenceChanged en el rest de las actividades donde las preferencias podrían cambiar?

El recolector de basura borra eso … debería considerar usar un contexto de aplicación en su lugar … o simplemente agregar el código cuando la aplicación se inicia … y luego agregar el oyente con el contexto de la aplicación …

Al leer datos legibles por Word compartidos por la primera aplicación, deberíamos

Reemplazar

 getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE); 

con

 getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS); 

en la segunda aplicación para obtener el valor actualizado en la segunda aplicación.