Au début, je pensais que la réponse de Moonsoo (la réponse acceptée) ne fonctionnerait pas pour moi car je ne peux pas initialiser mon setOnCheckedChangeListener()
dans le constructeur ViewHolder car je dois le lier à chaque fois pour qu'il obtienne une variable de position mise à jour. Mais il m'a fallu beaucoup de temps pour réaliser ce qu'il disait.
Voici un exemple de "l'appel de méthode circulaire" dont il parle:
public void onBindViewHolder(final ViewHolder holder, final int position) {
SwitchCompat mySwitch = (SwitchCompat) view.findViewById(R.id.switch);
mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
data.delete(position);
notifyItemRemoved(position);
//This will call onBindViewHolder, but we can't do that when we are already in onBindViewHolder!
notifyItemRangeChanged(position, data.size());
}
}
});
//Set the switch to how it previously was.
mySwitch.setChecked(savedSwitchState); //If the saved state was "true", then this will trigger the infinite loop.
}
Le seul problème avec cela, c'est que lorsque nous avons besoin d'initialiser le commutateur pour qu'il soit activé ou désactivé (à partir de l'état sauvegardé passé, par exemple), il appelle l'auditeur qui pourrait appeler nofityItemRangeChanged
qui appelle à onBindViewHolder
nouveau. Vous ne pouvez pas appeler onBindViewHolder
lorsque vous êtes déjà dans onBindViewHolder
], car vous ne pouvez pas notifyItemRangeChanged
si vous êtes déjà en train de signaler que la gamme d'articles a changé. Mais je n'avais besoin que de mettre à jour l'interface utilisateur pour l'afficher ou la désactiver, ne voulant en fait rien déclencher.
Voici la solution que j'ai apprise de la réponse de JoniDS qui empêchera la boucle infinie. Tant que nous définissons l'auditeur sur "null" avant de définir Checked, il mettra à jour l'interface utilisateur sans déclencher l'auditeur, évitant ainsi la boucle infinie. Ensuite, nous pouvons définir l'auditeur après.
Code de JoniDS:
holder.checkbox.setOnCheckedChangeListener(null);
holder.checkbox.setChecked(condition);
holder.checkbox.setOnCheckedChangeListener(checkedListener);
Solution complète à mon exemple:
public void onBindViewHolder(final ViewHolder holder, final int position) {
SwitchCompat mySwitch = (SwitchCompat) view.findViewById(R.id.switch);
//Set it to null to erase an existing listener from a recycled view.
mySwitch.setOnCheckedChangeListener(null);
//Set the switch to how it previously was without triggering the listener.
mySwitch.setChecked(savedSwitchState); //If the saved state was "true", then this will trigger the infinite loop.
//Set the listener now.
mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
data.delete(position);
notifyItemRemoved(position);
//This will call onBindViewHolder, but we can't do that when we are already in onBindViewHolder!
notifyItemRangeChanged(position, data.size());
}
}
});
}