2015-04-16 7 views
65

Od czasu wydania nowej wersji biblioteki pomocniczej (22x) metoda getPosition() klasy RecyclerView.ViewHolder została uznana za przestarzałą w miejsce metod wymienionych w temacie. Naprawdę nie dostaję różnicy od czytania dokumentów. Czy ktoś mógłby wyjaśnić różnicę w terminach laika?RecyclerView.ViewHolder - getLayoutPosition vs getAdapterPosition

Mam następujący przypadek użycia - podaję mojej karcie listę, a także chcę mieć możliwość powiązania dodatkowych informacji dla każdego elementu listy. Mam mapowanie od pozycji do dodatkowych, a mapowanie jest dostępne dla posiadaczy, dzięki czemu mogą pobrać dodatkową dla swojej pozycji i zrobić z nią rzeczy. W jaki sposób powinienem użyć posiadacza?

Co dzieje się z pozycjami uchwytów, gdy pozycje listy w indeksach 0 i 1 są miejscami zamienionymi? Co zwracają metody?

Odpowiedz

78

Jest to trudna sytuacja, przepraszam, że dokumenty nie są wystarczające.

Po zmianie zawartości adaptera (i wywołanie notify***()) RecyclerView żąda nowego układu. Od tego momentu, aż układ układu zdecyduje się na obliczenie nowego układu (< 16 ms), pozycja układu i położenie adaptera mogą nie być zgodne, ponieważ układ nie odzwierciedlił jeszcze zmian adaptera.

W twoim przypadku użycia, ponieważ twoje dane są powiązane z twoją zawartością adaptera (i zakładam, że dane są zmieniane w tym samym czasie ze zmianami adaptera), powinieneś używać adapterPosition.

Bądź jednak ostrożny, jeśli dzwonisz pod numer notifyDataSetChanged(), ponieważ powoduje on unieważnienie wszystkiego, RecyclerView nie wie, że pozycja adaptera ViewHolder jest obliczana, dopóki nie zostanie obliczony następny układ. W takim przypadku getAdapterPosition() zwróci RecyclerView#NO_POSITION (-1).

Ale powiedzmy, że jeśli już nazywany notifyItemInserted(0) The getAdapterPosition() z ViewHolder który był poprzednio w pozycji 0 rozpocznie powrocie 1 natychmiast. Tak długo, jak wysyłasz szczegółowe powiadomienia o zdarzeniach, zawsze jesteś w dobrym stanie (znamy pozycję adaptera, mimo że nowy układ nie jest jeszcze obliczany).

Inny przykład, jeśli robisz coś na kliknięciu przez użytkownika, jeśli getAdapterPosition() powraca NO_POSITION, najlepiej jest ignorować tego kliknięcia, bo nie wiem, co użytkownik kliknął (chyba że masz jakiś inny mechanizm, np stabilne identyfikatory do wyszukiwania przedmiot).

Edit Dla Kiedy Układ Pozycja jest dobry

Powiedzmy używasz LinearLayoutManager i chcesz uzyskać dostęp do ViewHolder powyżej aktualnie klikniętego elementu. W takim przypadku powinieneś użyć pozycji układu, aby uzyskać powyższy element.

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

Musisz użyć pozycji układu, ponieważ odpowiada to, co użytkownik aktualnie widzi na ekranie.

+1

Grałem trochę i okazało się, że metoda getAdapterPosition() zawsze zwraca -1 na mnie. Debugowałem go i powodem jest to, że kod w metodzie (ostateczny rodzic ViewParent = itemView.getParent(); if (! (Nadrzędny egzemplarz RecyclerView)) {return -1;} zawsze dostaje się do bloku if, tj. Widok recyklera nie jest rodzicem widoku mojej komórki.Jak to może być? Mój kod do utworzenia posiadacza to: return MyViewHolder (LayoutInflater.from (viewGroup.getContext()). inflate (R.layout.test_list_item, viewGroup, false)); (Ciąg dalszy w innym komentarzu.) – wujek

+0

Kiedy zmieniam kod, aby zadzwonić nadmuchać (R.layout.test_list_item, ViewGroup, true); (zwróć uwagę na polecenie "dołącz do root'a"), Android rzuca: java.lang.IllegalStateException: Określone dziecko ma już rodzica. Najpierw musisz wywołać metodę removeView() na rodzicu dziecka. Jaki jest więc właściwy sposób utworzenia widoku z widokiem prawidłowo połączonym z widokiem recyklera? O dziwo, nawet jeśli getAdapterPosition() zwraca -1, ponieważ rodzic jest zerowy, wszystko inne działa poprawnie. – wujek

+1

Parametr boolowski w inflatorze układu to "addToParent". Musi być fałszywe, ponieważ to LayoutManager ma obowiązek go dodać. Myślę, że wywołujecie getAdapterPosition w onBind, gdzie już minęło pozycję. Z technicznego punktu widzenia właściciel widoku reprezentuje tę pozycję po powrocie onBind. Przy okazji zaktualizowaliśmy pozycję getAdapter, aby zwrócić prawidłową pozycję (jeśli to możliwe), nawet jeśli jest ona odłączona, wkrótce zostanie udostępniona. – yigit