Zuerst dachte ich, Moonsoos Antwort (die akzeptierte Antwort) würde für mich nicht funktionieren, da ich meine setOnCheckedChangeListener()
im ViewHolder-Konstruktor nicht initialisieren kann, weil ich sie jedes Mal binden muss, damit sie eine aktualisierte Positionsvariable erhält. Aber ich habe lange gebraucht, um zu begreifen, was er sagte.
Hier ist ein Beispiel für den "zirkulären Methodenaufruf", von dem er spricht:
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.
}
Das einzige Problem dabei ist, dass, wenn wir den Schalter so initialisieren müssen, dass er ein- oder ausgeschaltet ist (z. B. aus dem zuvor gespeicherten Zustand), der Listener angerufen wird, der möglicherweise nofityItemRangeChanged
anruft und welche onBindViewHolder
erneut anruft . Sie können nicht anrufen, onBindViewHolder
wenn Sie bereits in onBindViewHolder
] sind, da Sie dies nicht können, notifyItemRangeChanged
wenn Sie bereits benachrichtigt werden, dass sich der Artikelbereich geändert hat.Aber ich musste nur die Benutzeroberfläche aktualisieren, um sie ein- oder auszuschalten, und wollte eigentlich nichts auslösen.
Hier ist die Lösung, die ich aus JoniDS 'Antwort gelernt habe und die die Endlosschleife verhindert. Solange wir den Listener auf "null" setzen, bevor wir "Checked" setzen, wird die Benutzeroberfläche aktualisiert, ohne den Listener auszulösen, wodurch die Endlosschleife vermieden wird. Dann können wir den Listener danach einstellen.
JoniDS Code:
holder.checkbox.setOnCheckedChangeListener(null);
holder.checkbox.setChecked(condition);
holder.checkbox.setOnCheckedChangeListener(checkedListener);
Vollständige Lösung für mein Beispiel:
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());
}
}
});
}