Come aggiornare / aggiornare un elemento specifico in RecyclerView


112

Sto cercando di aggiornare un elemento specifico in RecyclerView .

Storia: ogni volta che l'utente fa clic su un elemento, viene visualizzato AlertDialog. L'utente può digitare del testo facendo clic sul pulsante ok. Voglio mostrare questo testo in questo elemento e mostrare invisibile ImageView- dichiarato in XML e adattatore ViewHolder-

Ho usato questa funzione nel AlertDialogpulsante positivo per aggiornare l'elemento:

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);
}

Ma questo codice non solo cambia itemView nella posizione passata, ma cambia anche alcuni degli altri itemView!

Come devo modificare correttamente itemView specifico cliccandoci sopra?

Risposte:


98

È possibile utilizzare il notifyItemChanged(int position)metodo dalla classe RecyclerView.Adapter. Dalla documentazione:

Avvisare tutti gli osservatori registrati che l'elemento nella posizione è cambiato. Equivale a chiamare notifyItemChanged (position, null) ;.

Questo è un evento di modifica dell'articolo, non un evento di modifica strutturale. Indica che qualsiasi riflesso dei dati alla posizione non è aggiornato e deve essere aggiornato. L'articolo in posizione conserva la stessa identità.

Dato che hai già la posizione, dovrebbe funzionare per te.


9
L'ho già usato ma se voglio aggiornare la posizione 0, aggiorna la posizione 0, 9, 19, ...
Elgendy

Scusa, non ho capito il tuo commento. Quale posizione sta aggiornando? 0, 9 o l'intervallo tra 0 e 9?
Edson Menegatti

No, non è di portata, ogni volta che
aggiorno l'

@Learner Quando aggiorni il ViewHolder alla posizione 0, rimane aggiornato. Il RecyclerView riciclerà quel ViewHolder e lo utilizzerà per la posizione 9, quindi vedrai quei cambiamenti lì. Consiglio invece di impostare questo testo in onBindViewHolder () - in questo modo, ogni volta che un ViewHolder viene riciclato puoi controllarne la posizione e impostare il testo o rendere l'immagine visibile o qualsiasi altra cosa correttamente.
Cliabhach

@Cliabhach ancora lo stesso problema facendo i cambiamenti inonBindViewHolder()
Choletski

39

Aggiorna singolo elemento

  1. Aggiorna l'elemento dati
  2. Avvisare l'adattatore della modifica con notifyItemChanged(updateIndex)

Esempio

Cambia la voce "Pecora" in modo che dica "Mi piacciono le pecore".

Aggiorna singolo elemento

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

La mia risposta completa con più esempi è qui .


come fare se voglio che i dati aggiornati passino all'inizio
Choy

@Choy, dopo aver aggiornato i dati puoi spostarli nell'indice 0. Vedi la sezione Sposta elemento singolo di questo articolo
Suragch

11

Aggiungi il testo modificato all'elenco dei dati del modello

mdata.get(position).setSuborderStatusId("5");
mdata.get(position).setSuborderStatus("cancelled");
notifyItemChanged(position);

10

Penso di avere un'idea su come affrontare questo problema. L'aggiornamento equivale a eliminare e sostituire nella posizione esatta. Quindi rimuovo l'elemento da quella posizione utilizzando il codice seguente:

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

e quindi aggiungerei l'elemento in quella particolare posizione come mostrato di seguito:

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

Sto cercando di implementarlo ora. Ti darei un feedback quando avrò finito!


2
Stai facendo un passo in più. Basta sostituire l'elemento in posizione e chiamare l'elemento notifyItemChanged (posizione);
toshkinl

@toshkinl Come sapresti quando i dati provengono da JSONObject? senza posizione?
olajide

7

Ho avuto modo di risolvere questo problema catturando la posizione dell'elemento che doveva essere modificato e quindi nella chiamata dell'adattatore

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

, questo chiamerà onBindViewHolder (ViewHolder holder, int position) per questo elemento specifico in questa posizione specifica.


2

La soluzione sotto ha funzionato per me:

Su un elemento RecyclerView, l'utente farà clic su un pulsante ma un'altra vista come TextView si aggiornerà senza notificare direttamente l'adattatore:

Ho trovato una buona soluzione per questo senza utilizzare il metodo notifyDataSetChanged (), questo metodo ricarica tutti i dati di recyclerView quindi se hai un'immagine o un video all'interno dell'elemento, si ricaricheranno e l'esperienza dell'utente non sarà buona:

Ecco un esempio di clic su un'icona simile a ImageView e aggiornare solo un singolo TextView (è possibile aggiornare più viste allo stesso modo dello stesso elemento) per mostrare come l'aggiornamento del conteggio dopo aver aggiunto +1:

// 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
            }
        });
    }

1

Un modo che ha funzionato per me personalmente, è utilizzare i metodi dell'adattatore di recyclerview per gestire i cambiamenti nei suoi elementi.

Andrebbe in un modo simile a questo, creare un metodo nella visualizzazione del riciclatore personalizzato un po 'come questo:

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

0

Nella classe dell'adattatore, nel metodo onBindViewHolder, impostare ViewHolder su setIsRecyclable (false) come nel codice seguente.

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

    // Then your other codes
}

0

devi solo aggiungere il seguente codice nella finestra di dialogo di avviso al clic di salvataggio

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

0

Il problema è RecyclerView.Adatperche non fornisce alcun metodo che restituisca l'indice dell'elemento

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);
}

La mia soluzione alternativa è creare un'istanza di mappa per (elemento, posizione) s

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
}
  • il tipo di elemento (qui classe Friend) dovrebbe implementare hashCode()e equals()perché è la chiave in hashmap.

quando un elemento è cambiato,

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

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

  }

È bene definire un metodo di supporto

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

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

L'istanza della mappa ( Map<Friend, Integer> posMap) non è necessariamente richiesta. Se map non viene utilizzata, scorrendo l'elenco è possibile trovare la posizione di un elemento.


-1

Questo è anche il mio ultimo problema. Qui la mia soluzione uso il modello di dati e l'adattatore per il mio 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);

-1

se stai creando un oggetto e lo aggiungi alla lista che usi nel tuo adattatore, quando cambi un elemento della tua lista nell'adattatore anche tutti gli altri tuoi elementi cambiano in altre parole è tutta una questione di riferimenti e la tua lista no tenere copie separate di quel singolo oggetto.


-5

Nell'adattatore RecyclerView, dovresti avere un ArrayList e anche un metodo addItemsToList(items)per aggiungere elementi dell'elenco a ArrayList. Quindi puoi aggiungere elementi dell'elenco chiamando in adapter.addItemsToList(items)modo dinamico. Dopo che tutti gli elementi dell'elenco sono stati aggiunti a ArrayList, puoi chiamareadapter.notifyDataSetChanged() per visualizzare l'elenco.

È possibile utilizzare notifyDataSetChangednell'adattatore per RecyclerView


sì, ho ArrayList per i dati, funziona senza alcun problema, il mio problema nell'aggiornamento di un elemento specifico -esistente- in questo elenco
Elgendy

dovresti avere la posizione dell'elemento che si sta aggiornando, quindi devi solo mettere un nuovo elemento nella sua rispettiva posizione come mList.add (position) .setName ("new name"); quindi utilizzare mAdapter.notifyDataSetChanged ();
Nooruddin Lakhani

4
Questa risposta ignora il desiderio di aggiornare un singolo elemento. La chiamata notifyDataSetChanged () dovrebbe essere eseguita solo quando l'intero set di dati cambia.
Mark McClelland
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.