RecyclerView.ViewHolder - getLayoutPosition vs getAdapterPosition


90

Dalla nuova versione della libreria di supporto (22.x) il getPosition()metodo della RecyclerView.ViewHolderclasse è stato deprecato al posto dei metodi menzionati nell'argomento. Non capisco davvero la differenza dalla lettura dei documenti. Qualcuno potrebbe spiegare la differenza in termini profani?

Ho il seguente caso d'uso: do il mio adattatore a List e voglio anche essere in grado di associare informazioni extra per ogni voce dell'elenco. Ho una mappatura da posizione a extra e la mappatura è disponibile per i titolari in modo che possano recuperare l'extra per la loro posizione e fare cose con essa. Nel supporto, quale metodo devo usare?

Cosa succede con le posizioni del titolare quando gli elementi dell'elenco agli indici 0 e 1 vengono scambiati di posizione? Cosa restituiscono i metodi?

Risposte:


116

Questa è una situazione delicata, mi dispiace che i documenti non siano sufficienti.

Quando il contenuto dell'adattatore cambia (e tu chiami notify***()) RecyclerView richiede un nuovo layout. Da quel momento, fino a quando il sistema di layout non decide di calcolare un nuovo layout (<16 ms), la posizione del layout e la posizione dell'adattatore potrebbero non corrispondere perché il layout non ha ancora riflesso le modifiche dell'adattatore.

Nel tuo caso d'uso, poiché i tuoi dati sono correlati al contenuto dell'adattatore (e presumo che i dati vengano modificati contemporaneamente con i cambiamenti dell'adattatore), dovresti usare adapterPosition .

Fai attenzione però, se stai chiamando notifyDataSetChanged(), perché invalida tutto, RecyclerView non sa che la posizione dell'adattatore di ViewHolder fino a quando non viene calcolato il layout successivo. In tal caso, getAdapterPosition()restituirà RecyclerView#NO_POSITION(-1 ).

Ma diciamo che se hai chiamato notifyItemInserted(0), il getAdapterPosition()di ViewHolder che era precedentemente nella posizione 0inizierà a tornare 1immediatamente. Quindi, finché invii eventi di notifica granulari, sei sempre in buono stato (conosciamo la posizione dell'adattatore anche se il nuovo layout non è stato ancora calcolato).

Un altro esempio, se stai facendo qualcosa al clic dell'utente, se getAdapterPosition()ritorna NO_POSITION, è meglio ignorare quel clic perché non sai quale utente ha cliccato (a meno che tu non abbia qualche altro meccanismo, ad esempio ID stabili per cercare l'elemento).

Modifica per quando la posizione del layout è buona

Diciamo che stai usando LinearLayoutManagere vuoi accedere al ViewHolder sopra l'elemento attualmente cliccato. In tal caso, dovresti utilizzare la posizione del layout per ottenere l'elemento sopra.

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

È necessario utilizzare la posizione del layout perché corrisponde a ciò che l'utente sta attualmente vedendo sullo schermo.


1
Ho giocato un po 'e ho scoperto che il metodo getAdapterPosition () restituisce sempre -1 su di me. Ho eseguito il debug e il motivo è che il codice nel metodo (final ViewParent parent = itemView.getParent (); if (! (Parent instanceof RecyclerView)) {return -1;} entra sempre nel blocco if, cioè la vista riciclatore non è il genitore della mia visualizzazione cella. Come può essere? Il mio codice per creare il titolare è: return MyViewHolder (LayoutInflater.from (viewGroup.getContext ()). inflate (R.layout.test_list_item, viewGroup, false)); (Continua in un altro commento)
wujek

Quando cambio il codice per chiamare inflate (R.layout.test_list_item, viewGroup, true); (nota il vero per 'attach to root), Android lancia: java.lang.IllegalStateException: il figlio specificato ha già un genitore. Devi prima chiamare removeView () sul genitore del bambino. Qual è quindi il modo corretto per creare un supporto della vista con una vista che è collegata correttamente alla vista del riciclatore? Stranamente, anche se getAdapterPosition () restituisce -1 perché il genitore è nullo, tutto il resto funziona bene.
wujek

1
Il parametro booleano nel programma di gonfiaggio del layout è "addToParent". Deve essere falso perché è responsabilità di LayoutManager aggiungerlo. Penso che tu stia chiamando getAdapterPosition in onBind dove hai già superato la posizione. Tecnicamente, view holder rappresenta quella posizione dopo che onBind ritorna. A proposito, abbiamo aggiornato la posizione di getAdapter per restituire una posizione valida (se possibile) anche se è scollegata, verrà rilasciata presto.
yigit

Hai ragione, chiamo getAdapterPosition in onBind. Cosa dovrei fare in questo caso, invece, ho bisogno della posizione per ottenere alcune informazioni che influenzano gli stati di alcune opinioni. La chiamata a getLayoutPosition in questo caso va bene?
wujek

5
È necessario utilizzare il parametro position passato al metodo onBind.
yigit

2


Al fine di sostenere la differenza (s) di getAdapterPosition(), getLayoutPosition()e anche position; noteremmo i casi seguenti:

1. positionargomento nel onBindViewHolder()metodo:

Possiamo usare il positionper associare i dati alla vista ed è corretto usare l' positionargomento per farlo, ma non va bene usare l' positionargomento per gestire i clic degli utenti e se lo usi vedrai un avviso che ti dice "non trattare positioncome fissa e usa holder.getAdapterPosition()invece ".

2 getAdapterPosition().:

Questo metodo consiste sempre nella posizione dell'adattatore aggiornato del file holder. Significa che ogni volta che fai clic su un elemento, chiedi all'adattatore di esso position. così otterrai l'ultima posizione di questo elemento in termini di logica dell'adattatore.

3 getLayoutPosition().:

A volte, è necessario trovare i positiontermini del layout aggiornato (l'ultimo layout passato che l'utente sta vedendo ora), ad esempio: Se l'utente chiede il terzo positionpuò vedere e tu usi swipe/dismiss per elementi o applichi qualsiasi animazione o decorazioni per gli oggetti sarà meglio usare al getLayoutPosition()posto di getAdapterPosition(), perché sarai sempre sicuro di avere a che fare con la posizione degli oggetti in termini dell'ultima disposizione passata.


Per ulteriori informazioni su questo; vedere qui . . .

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.