So aktualisieren / aktualisieren Sie bestimmte Elemente in RecyclerView

111

Ich versuche, ein bestimmtes Element in zu aktualisieren RecyclerView.

Story: Immer wenn ein Benutzer auf ein Element klickt, wird es angezeigt AlertDialog. Der Benutzer kann Text eingeben, indem er auf die Schaltfläche OK klickt. Ich möchte diesen Text in diesem Artikel anzeigen und unsichtbar anzeigen ImageView- in XML und Adapter deklariert ViewHolder-

Ich habe diese Funktion in der AlertDialogpositiven Schaltfläche verwendet, um das Element zu aktualisieren:

private void updateListItem(int position) {
  View view = layoutManager.findViewByPosition(position);
  ImageView medicineSelected = (ImageView) view.findViewById(R.id.medicine_selected);
  medicineSelected.setVisibility(View.VISIBLE);
  TextView orderQuantity = (TextView) view.findViewById(R.id.order_quantity);
  orderQuantity.setVisibility(View.VISIBLE);
  orderQuantity.setText(quantity + " packet added!");

  medicinesArrayAdapter.notifyItemChanged(position);
}

Dieser Code ändert jedoch nicht nur die itemView an der übergebenen Position, sondern auch einige andere itemViews!

Wie soll ich eine bestimmte itemView korrekt ändern, indem ich darauf klicke?

Elgendy
quelle

Antworten:

98

Sie können die notifyItemChanged(int position)Methode aus der RecyclerView.Adapter-Klasse verwenden. Aus der Dokumentation:

Benachrichtigen Sie alle registrierten Beobachter, dass sich der Artikel an der Position geändert hat. Entspricht dem Aufruf von notifyItemChanged (position, null);.

Dies ist ein Elementänderungsereignis, kein Strukturänderungsereignis. Es zeigt an, dass jede Reflexion der Daten an der Position veraltet ist und aktualisiert werden sollte. Der Artikel an Position behält die gleiche Identität.

Da Sie die Position bereits haben, sollte es für Sie funktionieren.

Edson Menegatti
quelle
9
Ich habe es bereits verwendet, aber wenn ich Position 0 aktualisieren möchte, aktualisiert es Position 0, 9, 19, ...
Elgendy
Entschuldigung, habe Ihren Kommentar nicht verstanden. Welche Position wird aktualisiert? 0, 9 oder der Bereich zwischen 0 und 9?
Edson Menegatti
Nein, es ist kein Bereich, jedes Mal, wenn ich ein Element aktualisiere, werden auch unerwünschte Elemente aktualisiert
Elgendy
@Learner Wenn Sie den ViewHolder an Position 0 aktualisieren, bleibt er aktualisiert. Die RecyclerView wird recycelt , dass ViewHolder und es für 9 - Position verwenden, so dass Sie die Änderungen dort sehen. Ich empfehle, diesen Text stattdessen in onBindViewHolder () festzulegen. Auf diese Weise können Sie bei jedem Recycling eines ViewHolder seine Position überprüfen und Text festlegen oder das Bild sichtbar machen oder was auch immer richtig.
Cliabhach
@Cliabhach immer noch das gleiche Problem Änderungen inonBindViewHolder()
Choletski
39

Einzelne Elemente aktualisieren

  1. Aktualisieren Sie das Datenelement
  2. Benachrichtigen Sie den Adapter über die Änderung mit notifyItemChanged(updateIndex)

Beispiel

Ändern Sie das Element "Schafe" so, dass "Ich mag Schafe" angezeigt wird.

Einzelne Elemente aktualisieren

String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);

Meine vollständige Antwort mit weiteren Beispielen finden Sie hier .

Suragch
quelle
Wie mache ich das, wenn ich die aktualisierten Daten nach oben schalten möchte
Choy
@Choy, nachdem Sie die Daten aktualisiert haben, können Sie sie auf Index 0 verschieben. Siehe den Abschnitt
Einzelelement verschieben
11

Fügen Sie den geänderten Text Ihrer Modelldatenliste hinzu

mdata.get(position).setSuborderStatusId("5");
mdata.get(position).setSuborderStatus("cancelled");
notifyItemChanged(position);
Shamir Kp
quelle
10

Ich glaube, ich habe eine Idee, wie ich damit umgehen soll. Das Aktualisieren entspricht dem Löschen und Ersetzen an der genauen Position. Also entferne ich zuerst den Gegenstand von dieser Position mit dem folgenden Code:

public void removeItem(int position){
    mData.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, mData.size());
}

und dann würde ich den Artikel an dieser bestimmten Position hinzufügen, wie unten gezeigt:

public void addItem(int position, Landscape landscape){
    mData.add(position, landscape);
    notifyItemInserted(position);
    notifyItemRangeChanged(position, mData.size());
}

Ich versuche das jetzt umzusetzen. Ich würde dir ein Feedback geben, wenn ich fertig bin!

EGBENCHONG II J. Ayuk
quelle
2
Sie machen einen zusätzlichen Schritt. Ersetzen Sie einfach das Element an der Position und rufen Sie das Element notifyItemChanged (position) auf.
toshkinl
@toshkinl Woher wissen Sie, wann Daten von JSONObject stammen? ohne Position?
Olajide
7

Ich musste dieses Problem lösen, indem ich die Position des zu ändernden Elements und dann den Adapteraufruf abfing

public void refreshBlockOverlay(int position) {
    notifyItemChanged(position);
}

Dadurch wird onBindViewHolder (ViewHolder-Inhaber, int-Position) für dieses bestimmte Element an dieser bestimmten Position aufgerufen.

haneenCo
quelle
2

Die folgende Lösung hat bei mir funktioniert:

Bei einem RecyclerView-Element klickt der Benutzer auf eine Schaltfläche, aber eine andere Ansicht wie TextView wird aktualisiert, ohne den Adapter direkt zu benachrichtigen:

Ich habe eine gute Lösung dafür gefunden, ohne die notifyDataSetChanged () -Methode zu verwenden. Diese Methode lädt alle Daten von recyclerView neu. Wenn Sie also Bilder oder Videos in einem Element haben, werden diese neu geladen und die Benutzererfahrung ist nicht gut:

Hier ist ein Beispiel für das Klicken auf ein ImageView-ähnliches Symbol und das Aktualisieren nur einer einzelnen TextView (es ist möglich, mehr Ansichten auf dieselbe Weise wie bei demselben Element zu aktualisieren), um nach dem Hinzufügen von +1 die Aktualisierung der Anzahl anzuzeigen:

// View holder class inside adapter class
public class MyViewHolder extends RecyclerView.ViewHolder{

    ImageView imageViewLike;

    public MyViewHolder(View itemView) {
         super(itemView);

        imageViewLike = itemView.findViewById(R.id.imageViewLike);
        imageViewLike.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int pos = getAdapterPosition(); // Get clicked item position
                TextView tv = v.getRootView().findViewById(R.id.textViewLikeCount); // Find textView of recyclerView item
                resultList.get(pos).setLike(resultList.get(pos).getLike() + 1); // Need to change data list to show updated data again after scrolling
                tv.setText(String.valueOf(resultList.get(pos).getLike())); // Set data to TextView from updated list
            }
        });
    }
Touhid
quelle
1

Eine Möglichkeit, die für mich persönlich funktioniert hat, ist die Verwendung der Adaptermethoden von recyclerview, um mit Änderungen an den Elementen umzugehen.

In ähnlicher Weise würde es eine Methode erstellen, die in der Ansicht Ihres benutzerdefinierten Recyclers ungefähr so ​​aussieht:

public void modifyItem(final int position, final Model model) {
    mainModel.set(position, model);
    notifyItemChanged(position);
}
user3709410
quelle
0

Setzen Sie in Ihrer Adapterklasse in der onBindViewHolder-Methode ViewHolder wie im folgenden Code auf setIsRecyclable (false).

@Override
public void onBindViewHolder(RecyclerViewAdapter.ViewHolder p1, int p2)
{
    // TODO: Implement this method
    p1.setIsRecyclable(false);

    // Then your other codes
}
shankar_vl
quelle
0

Sie müssen nur den folgenden Code im Warnungsdialogfeld beim Klicken zum Speichern hinzufügen

          recyclerData.add(position, updateText.getText().toString());
          recyclerAdapter.notifyItemChanged(position);
Dhruvisha
quelle
0

Das Problem ist, RecyclerView.Adatperdass keine Methoden bereitgestellt werden, die den Index des Elements zurückgeben

public abstract static class Adapter<VH extends ViewHolder> {
  /**
   * returns index of the given element in adapter, return -1 if not exist
   */
  public int indexOf(Object elem);
}

Meine Problemumgehung besteht darin, eine Karteninstanz für (Element, Position) s zu erstellen

public class FriendAdapter extends RecyclerView.Adapter<MyViewHolder> {
  private Map<Friend, Integer> posMap ;
  private List<Friend> friends;

  public FriendAdapter(List<Friend> friends ) {
    this.friends = new ArrayList<>(friends);
    this.posMap = new HashMap<>();
    for(int i = 0; i < this.friends.size(); i++) {
      posMap.put(this.friends.get(i), i);
    }
  }

  public int indexOf(Friend friend) {
    Integer position = this.posMap.get(elem);
    return position == null ? -1 : position;
  }
  // skip other methods in class Adapter
}
  • Der Elementtyp (hier Klasse Friend) sollte implementiert werden hashCode()und equals()weil er der Schlüssel in der Hashmap ist.

wenn sich ein Element ändert,

  void someMethod() {
    Friend friend = ...;
    friend.setPhoneNumber('xxxxx');

    int position = friendAdapter.indexOf(friend);
    friendAdapter.notifyItemChanged(position);

  }

Es ist gut, eine Hilfsmethode zu definieren

public class FriendAdapter extends extends RecyclerView.Adapter<MyViewHolder> {

  public void friendUpdated(Friend friend) {
    int position = this.indexOf(friend);
    this.notifyItemChanged(position);
  }
}

Map instance ( Map<Friend, Integer> posMap) ist nicht unbedingt erforderlich. Wenn map nicht verwendet wird, kann durch Schleifen in der gesamten Liste die Position eines Elements ermittelt werden.

chmin
quelle
-1

Das ist auch mein letztes Problem. Hier meine Lösung Ich verwende Datenmodell und Adapter für meine RecyclerView

 /*Firstly, register your new data to your model*/
 DataModel detail = new DataModel(id, name, sat, image);

 /*after that, use set to replace old value with the new one*/
 int index = 4;
 mData.set(index, detail);

 /*finally, refresh your adapter*/
 if(adapter!=null)
    adapter.notifyItemChanged(index);
deya tri
quelle
-1

Wenn Sie ein Objekt erstellen und es der Liste hinzufügen, die Sie in Ihrem Adapter verwenden, ändern sich beim Ändern eines Elements Ihrer Liste im Adapter auch alle anderen Elemente. Mit anderen Worten, es geht nur um Referenzen und Ihre Liste nicht Halten Sie separate Kopien dieses einzelnen Objekts.

A.obhdel
quelle
-5

In Ihrem RecyclerView-Adapter sollten Sie eine ArrayList sowie eine Methode addItemsToList(items)zum Hinzufügen von Listenelementen zur ArrayList haben. Anschließend können Sie Listenelemente durch adapter.addItemsToList(items)dynamischen Aufruf hinzufügen . Nachdem alle Ihre Listenelemente zur ArrayList hinzugefügt wurden, können Sie aufrufen adapter.notifyDataSetChanged(), um Ihre Liste anzuzeigen.

Sie können die notifyDataSetChangedim Adapter für die RecyclerView verwenden

Nooruddin Lakhani
quelle
Ja, ich habe ArrayList für Daten, es funktioniert ohne Probleme, mein Problem beim Aktualisieren eines bestimmten vorhandenen Elements in dieser Liste
Elgendy
Sie sollten die Position des Elements haben, die aktualisiert wird, dann müssen Sie nur ein neues Element an die entsprechende Position setzen, wie mList.add (Position) .setName ("neuer Name"); Verwenden Sie dann mAdapter.notifyDataSetChanged ().
Nooruddin Lakhani
4
Diese Antwort ignoriert den Wunsch, ein einzelnes Element zu aktualisieren. Das Aufrufen von notifyDataSetChanged () sollte nur erfolgen, wenn sich der gesamte Datensatz ändert.
Mark McClelland