All'inizio ho pensato che la risposta di Moonsoo (la risposta accettata) non avrebbe funzionato per me perché non potevo inizializzare la mia setOnCheckedChangeListener()nel costruttore ViewHolder perché ho bisogno di associarla ogni volta in modo da ottenere una variabile di posizione aggiornata. Ma mi ci è voluto molto tempo per capire cosa stesse dicendo.
Ecco un esempio della "chiamata al metodo circolare" di cui sta parlando:
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.
}
L'unico problema con questo è che quando dobbiamo inizializzare l'interruttore per essere acceso o spento (dallo stato salvato in passato, ad esempio), sta chiamando l'ascoltatore che potrebbe chiamare nofityItemRangeChangedquali chiamate di onBindViewHoldernuovo. Non puoi chiamare onBindViewHolderquando sei già onBindViewHolder], perché non puoi notifyItemRangeChangedse stai già notificando che l'intervallo di articoli è cambiato. Ma avevo solo bisogno di aggiornare l'interfaccia utente per mostrarla on o off, non volendo effettivamente innescare nulla.
Ecco la soluzione che ho imparato dalla risposta di JoniDS che impedirà il ciclo infinito. Finché impostiamo il listener su "null" prima di impostare Checked, aggiornerà l'interfaccia utente senza innescare il listener, evitando il ciclo infinito. Quindi possiamo impostare l'ascoltatore dopo.
Codice JoniDS:
holder.checkbox.setOnCheckedChangeListener(null);
holder.checkbox.setChecked(condition);
holder.checkbox.setOnCheckedChangeListener(checkedListener);
Soluzione completa al mio esempio:
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());
}
}
});
}