Ich versuche, die Elemente einer Recyclingansicht mit notifyDataSetChanged () zu aktualisieren.
Dies ist meine onBindViewHolder () -Methode im recycleview-Adapter.
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
//checkbox view listener
viewHolder.getCheckbox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//update list items
notifyDataSetChanged();
}
});
}
Ich möchte die Listenelemente aktualisieren, nachdem ich ein Kontrollkästchen aktiviert habe. Ich bekomme jedoch eine illegale Ausnahme:"Cannot call this method while RecyclerView is computing a layout or scrolling"
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:2982)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:7493)
at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:4338)
at com.app.myapp.screens.RecycleAdapter.onRowSelect(RecycleAdapter.java:111)
Ich habe auch notifyItemChanged () verwendet, dieselbe Ausnahme. Gibt es eine geheime Möglichkeit zum Aktualisieren, um den Adapter darüber zu informieren, dass sich etwas geändert hat?
android
android-recyclerview
Arthur
quelle
quelle
Antworten:
Sie sollten die Methode 'setOnCheckedChangeListener ()' nach ViewHolder verschieben, der inneren Klasse Ihres Adapters.
onBindViewHolder()
ist keine Methode, die initialisiert wirdViewHolder
. Diese Methode ist ein Schritt zum Aktualisieren jedes Recyclingartikels. Wenn Sie anrufennotifyDataSetChanged()
,onBindViewHolder()
wird als die Nummer jedes Artikels mal angerufen.Wenn Sie also
notifyDataSetChanged()
in setzenonCheckChanged()
und initialisieren checkBox inonBindViewHolder()
, erhalten Sie Illegal wegen Kreismethodenaufruf.Klicken Sie auf das Kontrollkästchen -> onCheckedChanged () -> notifyDataSetChanged () -> onBindViewHolder () -> Kontrollkästchen setzen -> onChecked ...
Sie können dies einfach beheben, indem Sie ein Flag in den Adapter setzen.
Versuche dies,
quelle
AdapterViewObserver
währendonBindViewHolder()
im Gange.Sie können den vorherigen Listener einfach zurücksetzen, bevor Sie Änderungen vornehmen, und diese Ausnahme wird nicht angezeigt.
quelle
Die Verwendung von a
Handler
zum Hinzufügen von Elementen und Aufrufennotify...()
von hier aus hatHandler
das Problem für mich behoben.quelle
Ich weiß es nicht gut, aber ich hatte auch das gleiche Problem. Ich habe das mit
onClickListner
on gelöstcheckbox
Versuchen Sie dies, dies kann helfen!
quelle
quelle
Wenn Sie den Nachrichtenfehler haben:
Einfach, machen Sie einfach, was die Ausnahme verursacht in:
quelle
Eine einfache Lösung gefunden -
Hier erstellen wir eine ausführbare Datei, um ItemChanged für eine Position zu benachrichtigen, wenn recyclerview bereit ist, damit umzugehen.
quelle
Ihr CheckBox-Element ändert sich beim Aufruf in Drawable,
notifyDataSetChanged();
sodass diese Ausnahme auftreten würde. Versuchen Sie,notifyDataSetChanged();
nach Ihrer Ansicht anzurufen . Beispielsweise:quelle
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:
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 welcheonBindViewHolder
erneut anruft . Sie können nicht anrufen,onBindViewHolder
wenn Sie bereits inonBindViewHolder
] 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:
Vollständige Lösung für mein Beispiel:
quelle
Warum nicht den
RecyclerView.isComputingLayout()
Status wie folgt überprüfen ?quelle
Während das Element vom Layout-Manager gebunden wird, ist es sehr wahrscheinlich, dass Sie den aktivierten Status Ihres Kontrollkästchens festlegen, das den Rückruf auslöst.
Dies ist natürlich eine Vermutung, da Sie nicht den vollständigen Stack-Trace veröffentlicht haben.
Sie können den Adapterinhalt nicht ändern, während RV das Layout neu berechnet. Sie können dies vermeiden, indem Sie notifyDataSetChanged nicht aufrufen, wenn der aktivierte Status des Elements dem im Rückruf gesendeten Wert entspricht (was der Fall ist, wenn der Aufruf
checkbox.setChecked
den Rückruf auslöst).quelle
Verwenden Sie das Kontrollkästchen onClickListner on anstelle von OnCheckedChangeListener. Dadurch wird das Problem behoben
quelle
Bevor
notifyDataSetChanged()
Sie dies mit dieser Methode überprüfen:recyclerView.IsComputingLayout()
quelle
Einfache Verwendung Beitrag:
quelle
Ich bin genau auf dieses Problem gestoßen! Nachdem Moonsoos Antwort mein Boot nicht wirklich schwebte, spielte ich ein bisschen herum und fand eine Lösung, die für mich funktionierte.
Hier ist zunächst ein Teil meines Codes:
Sie werden feststellen, dass ich den Adapter speziell über die Position benachrichtige, die ich ändere, anstatt über den gesamten Datensatz, wie Sie es tun. Obwohl ich nicht garantieren kann, dass dies für Sie funktioniert, habe ich das Problem gelöst, indem ich meinen
notifyItemChanged()
Anruf in einen Try / Catch-Block eingeschlossen habe. Dies hat einfach die Ausnahme abgefangen, aber mein Adapter konnte trotzdem die Statusänderung registrieren und die Anzeige aktualisieren!Hoffe das hilft jemandem!
EDIT: Ich gebe zu, dies ist wahrscheinlich nicht die richtige / ausgereifte Art, das Problem zu behandeln, aber da es keine Probleme zu verursachen scheint, wenn die Ausnahme unbehandelt bleibt, dachte ich, ich würde sie teilen, falls es gut wäre genug für jemand anderen.
quelle
Dies geschieht, weil Sie wahrscheinlich den "Listener" festlegen, bevor Sie den Wert für diese Zeile konfigurieren. Dadurch wird der Listener ausgelöst, wenn Sie den Wert für das Kontrollkästchen "konfigurieren".
Was Sie tun müssen, ist:
quelle
quelle
verwenden Sie einfach
isPressed()
VerfahrenCompoundButton
inonCheckedChanged(CompoundButton compoundButton, boolean isChecked)
zB
quelle
Ich hatte das gleiche Problem mit der Checkbox und dem RadioButton. Ersetzen
notifyDataSetChanged()
durchnotifyItemChanged(position)
gearbeitet. IchisChecked
habe dem Datenmodell ein Boolesches Feld hinzugefügt . Dann habe ich den Booleschen Wert aktualisiert und inonCheckedChangedListener
aufgerufennotifyItemChanged(adapterPosition)
. Dies ist vielleicht nicht der beste Weg, hat aber für mich funktioniert. Der boolesche Wert wird verwendet, um zu überprüfen, ob das Element aktiviert ist.quelle
meist geschieht es beacause notifydatasetchanged Berufung onCheckedchanged Ereignis von Kontrollkästchen , und in diesem Fall wieder dort notifydatasetchanged .
Um es zu lösen, können Sie einfach überprüfen, ob das Kontrollkästchen programmgesteuert aktiviert ist oder der Benutzer es gedrückt hat. Es gibt eine Methode, die dafür gedrückt wird.
Wickeln Sie also den gesamten Listener-Code in die isPressed-Methode ein. und es ist geschafft.
quelle
Ich habe stundenlang unter diesem Problem gelitten und so können Sie es beheben. Aber bevor Sie begonnen haben, gibt es einige Bedingungen für diese Lösung.
MODELLKLASSE
CHECKBOX in der ADAPTERKLASSE
ADAPTER CLASS CONSTRUCTOR & LISTE DES MODELLS
ONBINDVIEW [Bitte verwenden Sie onclick anstelle von onCheckChange]
}}
quelle
Bei mir trat ein Problem auf, als ich EditText durch Fertig, Zurück oder externe Eingabeberührung verließ. Dadurch wird das Modell mit dem eingegebenen Text aktualisiert und anschließend die Recycler-Ansicht über die Beobachtung von Live-Daten aktualisiert.
Das Problem war, dass Cursor / Fokus in EditText bleiben.
Wenn ich den Fokus gelöscht habe, indem ich:
Benachrichtigungsdaten geändert Methode der Recycler-Ansicht hat diesen Fehler nicht mehr ausgelöst.
Ich denke, dies ist einer der möglichen Gründe / Lösungen für dieses Problem. Es ist möglich, dass diese Ausnahme auf andere Weise behoben werden kann, da sie aus ganz anderen Gründen verursacht werden kann.
quelle