onSharedPreferenceChanged pas tiré si le changement se produit dans une activité séparée?

StackOverflow https://stackoverflow.com/questions/3799038

  •  05-10-2019
  •  | 
  •  

Question

Je l'ai mis en œuvre onSharedPreferenceChanged dans mon activité principale.

Si je change les préférences de l'activité principale, mes feux de l'événement.

Si je change les préférences à travers mon écran Préférences (PreferenceActivity) mon événement ne se déclenche pas lorsque les préférences sont modifiées (parce qu'il est une activité distincte et séparée pour référence sharedPreferences?)

Quelqu'un at-il une recommandation de la façon dont je devrais aller sur le dépassement de cette situation?

Merci!

EDIT1: J'ai essayé d'ajouter le gestionnaire d'événement dans mon activité de préférence mais il n'a jamais incendies. La méthode suivante est appelée pendant onCreate de mon activité de préférence. Quand je change les valeurs, il n'imprime le message (msg() est une enveloppe 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
        }
    });
}
Était-ce utile?

La solution

Le OnSharedPreferenceChangeListener reçoit les déchets collectés dans votre cas si vous utilisez une classe anonyme.

Pour résoudre ce problème utilisation le code suivant dans PreferenceActivity d'enregistrer et désenregistrer un écouteur de changement:

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 il faut savoir que l'auditeur ne s'appelle si la valeur réelle change. Réglage de la même valeur à nouveau ne se déclenche pas l'auditeur.

voir aussi SharedPreferences.onSharedPreferenceChangeListener pas appelé constamment

Autres conseils

Cela arrive parce que garbage collector. ses œuvres qu'une seule fois. alors la référence est avec les déchets ménagers. afin de créer champ d'instance pour l'auditeur.

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 déclenché lorsque j'ai changé booléen de true à false, ou vice-versa.

Après avoir beaucoup lu, et refactoring, commutation contexts/inner de classes/privates/static/ et autres, je me suis rendu mon (stupide) Erreur:

Le onSharedPreferenceChanged est uniquement appelé si quelque chose change. Seulement. Jamais.

Au cours de mes tests, j'étais tellement stupide de cliquer sur le même bouton tout le temps, attribuant ainsi la même valeur booléenne à la préférence tout le temps, il n'a jamais changé.

Hope this helps quelqu'un !!

Une autre façon d'éviter le problème est de rendre votre activité la classe auditeur. Comme il n'y a qu'une seule méthode de remplacement avec un nom distinctif que vous pouvez faire ceci:

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 a parlé d'une MainActivity écoute de changements de réglage dans un PreferenceActivity. Le demandeur a ensuite ajouté un « EDIT1 » et a changé la question à l'écoute dans le PreferenceActivity lui-même. C'est plus facile que l'ancien et semble être ce que toutes les réponses supposent. Mais si vous voulez encore l'ancien scénario?

Eh bien, cela fonctionnera aussi, mais ne pas utiliser onResume () et OnPause () pour enregistrer et désenregistrer l'auditeur. Cela provoquera l'auditeur d'être sans effet parce que les feuilles de l'utilisateur du MainActivity lorsqu'ils utilisent le PreferenceActivity (ce qui est logique quand on y pense). Donc, cela va fonctionner, mais votre MainActivity sera toujours à l'écoute en arrière-plan, même lorsque l'utilisateur ne l'utilise pas. Une sorte de gaspillage de ressources non? Donc, il y a une autre solution qui semble fonctionner, il suffit d'ajouter une méthode pour onResume () relise toutes les préférences. De cette façon, lorsqu'un utilisateur se termine l'édition des préférences dans un PreferenceActivity, les MainActivity vont les ramasser quand l'utilisateur revient à vous et ne pas besoin d'un auditeur à tous .

Quelqu'un s'il vous plaît laissez-moi savoir s'ils voient un problème avec cette approche.

Pourquoi ne pas ajouter juste un onSharedPreferenceChanged dans le reste des activités où les préférences pourraient changer?

Le garbage collector efface ... que vous devriez envisager d'utiliser un contexte d'application à la place ... ou tout simplement ajouter le code lorsque app catapultes ... puis ajoutez le l'auditeur avec le contexte de l'application ...

Considérez maintenant PreferencesChangeListener dans Android App instance de classe. Bien qu'il soit pas une référence solution de stockage propre à l'intérieur App devrait arrêter GC de déchets collecte de votre écoute et vous devriez toujours être en mesure de recevoir des mises à jour de changement DB. Rappelez-vous que gestionnaire de préférence ne pas enregistrer une forte référence à 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
        }
    }
}

Lors de la lecture de mots données lisibles partagées par la première application, nous devrions

Remplacer

getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);

avec

getSharedPreferences("PREF_NAME", Context.MODE_MULTI_PROCESS);

dans la deuxième application pour obtenir la valeur mise à jour dans la deuxième application.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top