J'ai implémenté onSharedPreferenceChanged
dans mon activité principale.
Si je modifie les préférences dans l'activité principale, mon événement est déclenché.
Si je modifie les préférences via mon écran de préférences (PreferenceActivity
), mon événement ne se déclenche PAS lorsque les préférences sont modifiées (car il s'agit d'une activité distincte et d'une référence distincte aux références partagées?)
Quelqu'un a-t-il une recommandation sur la manière dont je devrais agir pour surmonter cette situation?
Merci!
EDIT1: J'ai essayé d'ajouter le gestionnaire d'événements directement dans mon activité de préférence, mais il ne s'est jamais déclenché. La méthode suivante est appelée lors de l’activité de création de mon activité onCreate. Lorsque je change de valeur, le message n'est jamais imprimé (msg()
est un wrapper pour 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
}
});
}
Si vous utilisez une classe anonyme, la variable OnSharedPreferenceChangeListener
est collectée dans votre cas.
Pour résoudre ce problème, utilisez le code suivant dans PreferenceActivity
pour enregistrer et désenregistrer un écouteur de modification:
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
}
De plus, sachez que l'auditeur n'est appelé que si la valeur réelle change. Redéfinir la même valeur ne déclenchera pas l'auditeur.
voir aussi SharedPreferences.onSharedPreferenceChangeListener n'étant pas appelé de manière cohérente
Cela se produit parce que garbage collector. cela ne fonctionne qu'une fois. alors la référence est collectée comme une poubelle. alors créez un champ d'instance pour le programme d'écoute.
private OnSharedPreferenceChangeListener listner;
listner = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
//implementation goes here
}
};
prefs.registerOnSharedPreferenceChangeListener(listner);
Je suis arrivé ici, comme beaucoup d'autres, parce que mon auditeur ne sera pas viré lorsque je changerai son booléen de true
à false
, ou vice-versa.
Après beaucoup de lecture et de refactorisation, en passant de contexts/inner
à classes/privates/static/
et similaires, j'ai réalisé mon erreur (stupide):
La onSharedPreferenceChanged
est seulement appelé si quelque chose change. Seulement. Déjà.
Au cours de mes tests, j'étais si bête de cliquer tout le temps sur le même bouton, en assignant ainsi la même valeur booléenne à la préférence tout le temps, afin qu'elle ne change jamais.
J'espère que ça aide quelqu'un !!
Une autre façon d’éviter le problème est de faire de votre activité la classe d’auditeur. Comme il n'y a qu'une seule méthode de substitution avec un nom distinctif, vous pouvez le faire:
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)
{
...
}
}
Notez que la question initiale parlait d'une MainActivity écoutant les modifications de paramètres dans une PreferenceActivity. Le demandeur a ensuite ajouté "EDIT1" et a changé la question pour écouter dans PreferenceActivity lui-même. C'est plus facile que l'ancien et semble être ce que toutes les réponses supposent. Mais que faire si vous voulez toujours l'ancien scénario?
Eh bien, cela fonctionnera aussi, mais n'utilisez pas OnResume () et OnPause () pour enregistrer et annuler l'enregistrement de l'écouteur. Cela risquerait de rendre l'auditeur inefficace, car l'utilisateur quitte MainActivity lorsqu'il utilise PreferenceActivity (ce qui est logique lorsque vous y réfléchissez). Cela fonctionnera donc, mais votre MainActivity écoutera toujours en arrière-plan, même lorsque l’utilisateur ne l’utilise pas. Un gaspillage de ressources, n'est-ce pas? Donc, il y a une autre solution qui semble fonctionner, ajoutez simplement une méthode à OnResume () pour relire toutes les préférences. Ainsi, lorsqu'un utilisateur finit de modifier les préférences dans PreferenceActivity, MainActivity les reprendra lorsque l'utilisateur y reviendra et que vous n'avez pas besoin d'un écouteur du tout .
Quelqu'un s'il vous plaît faites le moi savoir si ils voient un problème avec cette approche.
Pourquoi ne pas simplement ajouter une onSharedPreferenceChanged
dans le reste des activités où les préférences pourraient changer?
Le ramasse-miettes efface cela ... vous devriez plutôt envisager d'utiliser un contexte d'application ... ou tout simplement ajouter le code au lancement de l'application ... puis ajoutez l'écouteur avec le contexte d'application ...
Pensez à conserver PreferencesChangeListener dans l'instance Android App class. Bien que ce ne soit PAS une solution propre stockant une référence dans App, cela devrait empêcher le GC de récupérer votre auditeur et vous devriez toujours pouvoir recevoir les mises à jour des modifications de base de données. Rappelez-vous que le gestionnaire de préférences ne pas stocke une référence forte à l'auditeur! ( 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)
}
}
et
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
}
}
}