RecyclerView.ViewHolder - getLayoutPosition vs getAdapterPosition

84

Seit der neuen Version der Unterstützungsbibliothek (22.x) ist die getPosition()Methode der RecyclerView.ViewHolderKlasse anstelle der im Thema genannten Methoden veraltet. Ich verstehe den Unterschied nicht wirklich vom Lesen der Dokumente. Könnte jemand den Unterschied in Laienbegriffen erklären?

Ich habe den folgenden Anwendungsfall: Ich gebe meinem Adapter ein Listund möchte außerdem zusätzliche Informationen für jedes Listenelement zuordnen können. Ich habe eine Zuordnung von Position zu Extra, und die Zuordnung steht den Inhabern zur Verfügung, damit sie das Extra für ihre Position abrufen und damit arbeiten können. Welche Methode soll ich im Inhaber verwenden?

Was passiert mit den Inhaberpositionen, wenn Listenelemente an den Indizes 0 und 1 vertauscht werden? Was geben die Methoden zurück?

Wujek
quelle

Antworten:

112

Dies ist eine schwierige Situation. Es tut uns leid, dass die Dokumente nicht ausreichen.

Wenn sich der Adapterinhalt ändert (und Sie aufrufen notify***()), fordert RecyclerView ein neues Layout an. Von diesem Moment an, bis das Layoutsystem beschließt, ein neues Layout zu berechnen (<16 ms), stimmen Layoutposition und Adapterposition möglicherweise nicht überein, da das Layout noch keine Adapteränderungen widerspiegelt.

In Ihrem Anwendungsfall sollten Sie verwenden, da Ihre Daten mit dem Inhalt Ihres Adapters zusammenhängen (und ich gehe davon aus, dass die Daten gleichzeitig mit den Änderungen des Adapters geändert werden) adapterPosition.

Seien Sie jedoch vorsichtig, wenn Sie anrufen notifyDataSetChanged(), da dies alles ungültig macht. RecyclerView kennt die Adapterposition von ViewHolder erst, wenn das nächste Layout berechnet wird. In diesem Fall getAdapterPosition()wird return RecyclerView#NO_POSITION( -1).

Angenommen, Sie haben angerufen notifyItemInserted(0), und der getAdapterPosition()zuvor an Position befindliche ViewHolder 0kehrt 1sofort zurück. Solange Sie granulare Benachrichtigungsereignisse auslösen, sind Sie immer in einem guten Zustand (wir kennen die Adapterposition, obwohl das neue Layout noch nicht berechnet wurde).

Ein weiteres Beispiel, wenn Sie etwas auf Benutzer klicken Sie tun, wenn getAdapterPosition()zurückkehrt NO_POSITION, ist es am besten , dass die Klick zu ignorieren , weil Sie nicht wissen , welche Benutzer geklickt hat (es sei denn , Sie einen anderen Mechanismus haben, zum Beispiel stabile ids das Element Lookup).

Bearbeiten für, wenn die Layoutposition gut ist

Nehmen wir an, Sie verwenden LinearLayoutManagerden ViewHolder über dem aktuell angeklickten Element und möchten darauf zugreifen. In diesem Fall sollten Sie die Layoutposition verwenden, um das obige Element zu erhalten.

mRecyclerView.findViewHolderForLayoutPosition(myViewHolder.getLayoutPosition() - 1)

Sie müssen die Layoutposition verwenden, da sie mit der aktuellen Position des Benutzers auf dem Bildschirm übereinstimmt.

Yigit
quelle
1
Ich habe ein bisschen herumgespielt und es stellte sich heraus, dass die Methode getAdapterPosition () immer -1 für mich zurückgibt. Ich habe es debuggt und der Grund dafür ist, dass der Code in der Methode (final ViewParent parent = itemView.getParent (); if (! (Übergeordnete Instanz von RecyclerView)) {return -1;} immer in den if-Block gelangt, dh in die Recycler-Ansicht ist nicht das übergeordnete Element meiner Zellenansicht. Wie kann es sein? Mein Code zum Erstellen des Halters lautet: return MyViewHolder (LayoutInflater.from (viewGroup.getContext ()). inflate (R.layout.test_list_item, viewGroup, false)); (Fortsetzung in einem anderen Kommentar.)
Wujek
Wenn ich den Code so ändere, dass inflate aufgerufen wird (R.layout.test_list_item, viewGroup, true); (Beachten Sie das True für 'An Root anhängen). Android löst Folgendes aus: java.lang.IllegalStateException: Das angegebene untergeordnete Element hat bereits ein übergeordnetes Element. Sie müssen removeView () zuerst auf dem übergeordneten Element des Kindes aufrufen. Wie kann also ein Ansichtshalter mit einer Ansicht erstellt werden, die korrekt an die Recycler-Ansicht angehängt ist? Seltsamerweise funktioniert alles andere einwandfrei, selbst wenn getAdapterPosition () -1 zurückgibt, weil das übergeordnete Element null ist.
Wujek
1
Der boolesche Parameter im Layout Inflator ist "addToParent". Es muss falsch sein, da LayoutManager dafür verantwortlich ist, es hinzuzufügen. Ich denke, Sie rufen getAdapterPosition in onBind auf, wo Ihnen die Position bereits übergeben wurde. Technisch gesehen repräsentiert der Ansichtsinhaber diese Position, nachdem onBind zurückgekehrt ist. Übrigens haben wir die Position getAdapter aktualisiert, um eine gültige Position (falls möglich) zurückzugeben, auch wenn sie getrennt ist. Sie wird bald veröffentlicht.
Yigit
Sie haben Recht, ich rufe getAdapterPosition in onBind auf. Was soll ich stattdessen in diesem Fall tun? Ich brauche die Position, um Informationen zu erhalten, die den Zustand einiger Ansichten beeinflussen. Ist es in diesem Fall in Ordnung, getLayoutPosition aufzurufen?
Wujek
5
Sie sollten den Positionsparameter verwenden, der an die onBind-Methode übergeben wird.
Yigit
1


Um die Differenz (en) der argumentieren getAdapterPosition(), getLayoutPosition()und auch position; Wir würden die folgenden Fälle bemerken:

1. positionArgument in onBindViewHolder()Methode:

Wir können die Verwendung positionzu binden Daten zur Ansicht und es ist in Ordnung zu verwenden positionArgument , dies zu tun, aber es ist nicht in Ordnung zu verwenden positionArgument handle Benutzer klickt und wenn Sie es verwendet wird , wird eine Warnung sagt Ihnen , „nicht zu behandeln sehen , positionwie behoben und holder.getAdapterPosition()stattdessen verwenden ".

2 . getAdapterPosition():

Diese Methode besteht immer aus der Position des aktualisierten Adapters des holder. Wenn Sie auf ein Element klicken, fragen Sie den Adapter danach position. So erhalten Sie die neueste Position dieses Elements in Bezug auf die Adapterlogik.

3 . getLayoutPosition():

Manchmal ist es erforderlich, positiondas aktualisierte Layout zu ermitteln (das zuletzt übergebene Layout, das der Benutzer jetzt sieht), zum Beispiel: Wenn der Benutzer nach dem dritten fragt, das positioner sehen kann, und Sie swipe/ dismissfür Elemente verwenden oder eine Animation anwenden oder Dekorationen für die Einzelteile wird es besser sein zu verwenden , getLayoutPosition()statt getAdapterPosition(), weil Sie immer sicher sein, dass Sie mit dem Artikel Position in Bezug auf die neuesten weitergegeben Layout handelt.


Weitere Informationen hierzu; siehe hier . . .

elyar abad
quelle