Android Recyclerview vs ListView z Viewholder

148

Niedawno natknąłem się na Androida, RecyclerViewktóry został wydany z Androidem 5.0 i wydaje się, że RecyclerViewjest to po prostu zamknięty w sobie tradycyjny ListViewwzorzec ViewHolder, który promuje ponowne użycie widoku, zamiast tworzyć go za każdym razem.

Jakie są inne korzyści z używania RecyclerView? Jeśli oba mają ten sam efekt pod względem wydajności, dlaczego ktoś miałby preferować RecyclerView?

Edytować

Odkryłem, że ludzie zadawali podobne pytanie, a odpowiedzi nie są rozstrzygające, dodając je tutaj w celu prowadzenia dokumentacji.

Recyclerview vs Listview

Czy powinniśmy używać RecyclerView, aby zastąpić ListView?

Dlaczego RecyclerView nie ma onItemClickListener ()? i czym różni się RecyclerView od Listview?

Mushtaq Jameel
źródło
4
Ponieważ RecyclerViewjest znacznie szybszy i bardziej wszechstronny z dużo lepszym interfejsem API. Rzeczy takie jak animowanie dodawania lub usuwania elementów są już zaimplementowane w programie RecyclerViewbez konieczności wykonywania jakichkolwiek czynności. Nie ma co do tego wątpliwości, wyrzuć swoje ListViewdo kosza na śmieci, RecyclerViewjest tu po to, żeby ukraść przedstawienie.
Xaver Kapeller,
4
Możesz skojarzyć menedżera układu z RecyclerView, aby nie był ograniczony do list przewijanych w pionie. To dość potężna dodatkowa funkcjonalność.
Alan
@Alan - Co masz na myśli mówiąc „nie ogranicza się do list przewijanych w pionie”? Czy chcesz powiedzieć, że widok Kosza może działać jako „symbol zastępczy” dla widoków Gridviews i ListViews?
Mushtaq Jameel
@XaverKapeller - Byłoby wspaniale, gdybyś mógł wymienić różnice między nimi i odpowiedzieć na pytanie zamiast komentarza, aby w przyszłości mogło to pomóc mnie i innym, którzy mogą się zastanawiać nad tym samym?
Mushtaq Jameel
@Alan - Czy mógłbyś podać trochę szczegółów o tym, co masz na myśli, i odpowiedzieć na pytanie zamiast komentarza. Dzięki za
poświęcenie

Odpowiedzi:

289

Wraz z pojawieniem się Androida Lollipop, RecyclerView pojawił się oficjalnie. RecyclerView jest znacznie bardziej wydajny, elastyczny i stanowi główne ulepszenie w porównaniu z ListView . Postaram się szczegółowo to wyjaśnić.

1) Wzorzec ViewHolder

W ListView zaleca się użycie wzorca ViewHolder, ale nigdy nie było to przymusem. W przypadku RecyclerView jest to obowiązkowe przy użyciu klasy RecyclerView.ViewHolder . Jest to jedna z głównych różnic między ListView i RecyclerView.

To sprawia, że ​​rzeczy w RecyclerView są nieco bardziej złożone, ale wiele problemów, z którymi mieliśmy do czynienia w ListView, zostało skutecznie rozwiązanych.

2) LayoutManager

To kolejne ogromne ulepszenie wprowadzone do RecyclerView. W ListView jedynym dostępnym typem widoku jest pionowy ListView. Nie ma nawet oficjalnego sposobu na zaimplementowanie poziomego ListView.

Teraz używając RecyclerView, możemy mieć plik

i) LinearLayoutManager - który obsługuje zarówno listy pionowe, jak i poziome,

ii) StaggeredLayoutManager - który obsługuje Pinteresta jak listy schodkowe,

iii) GridLayoutManager - który obsługuje wyświetlanie siatek, jak widać w aplikacjach Galerii.

A najlepsze jest to, że możemy to wszystko robić dynamicznie, jak chcemy.

3) Animator przedmiotów

ListViews nie obsługuje dobrych animacji, ale RecyclerView nadaje im zupełnie nowy wymiar. Przy użyciu klasy RecyclerView.ItemAnimator animowanie widoków staje się bardzo łatwe i intuicyjne.

4) dekoracja przedmiotu

W przypadku ListViews dynamiczne dekorowanie elementów, takich jak dodawanie obramowań lub separatorów, nigdy nie było łatwe. Jednak w przypadku RecyclerView klasa RecyclerView.ItemDecorator daje programistom ogromną kontrolę, ale sprawia, że ​​jest to nieco bardziej czasochłonne i złożone.

5) OnItemTouchListener

Przechwytywanie kliknięć elementów w ListView było proste dzięki interfejsowi AdapterView.OnItemClickListener . Ale RecyclerView daje znacznie więcej możliwości i kontroli programistom dzięki RecyclerView.OnItemTouchListener ( nie jest już obsługiwany, zapoznaj się z AndroidX ), ale komplikuje to nieco programistę.

Mówiąc prościej, RecyclerView jest znacznie bardziej konfigurowalny niż ListView i daje dużą kontrolę i możliwości programistom.

Aritra Roy
źródło
34
Dobra odpowiedź. Kilka dodatkowych ogromnych zalet: RecyclerView przygotowuje widok tuż przed i za widocznymi wpisami, co jest świetne, jeśli pobierasz mapy bitowe w tle. Wydajność jest znacznie szybsza, zwłaszcza jeśli używasz RecyclerView.setHasFixedSize. Stary ListView opiera się na założeniu, że nie ma możliwości wstępnego obliczenia lub buforowania rozmiaru wpisów na liście, co powoduje szalone komplikacje podczas przewijania i wykonywania układu. Przyzwyczajenie się do tego zajmuje trochę czasu, ale kiedy już to zrobisz, już nigdy nie wrócisz.
Robin Davies
@RobinDavies Doskonała uwaga. Dzięki za informację. Ale nie będzie to miało sensu, jeśli rozmiary przedmiotów będą różne.
Aritra Roy
@AritraRoy Recyclerview obsługuje tylko Lollipop lub api 14+ (Android 4+) także? .... jak czytam „po Lollipopie: w większości miejsc
Animesh Mangla
2
Hej, Aritra, w porównaniu do ListView, jeśli ListView również używa wzorca ViewHolder, który z nich działa wydajniej? Czy Recyler zobaczy lepiej, używając fps lub innego podobnego kryterium? thx ~
RxRead
@RxRead: Patrz komentarz Robina, rozróżnia on RecyclerView Vs ListView z wzorcem posiadacza widoku na podstawie wydajności.
Parag Kadam,
10

Innym plusem użycia RecycleViewjest animacja, można to zrobić w dwóch wierszach kodu

RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
        recyclerView.setItemAnimator(itemAnimator);

Ale widżet jest nadal surowy, np. Nie możesz utworzyć nagłówka i stopki .

Etun
źródło
5
I nigdy nie będziesz w stanie utworzyć nagłówka i stopki w tym sensie. To tylko inne typy widoku w Twojej karcie. Widok listy otacza adapter HeaderViewListAdapteri dodaje obsługę nagłówka w tle. Dzięki RecyclerView, że jesteś jedną kontrolę.
Eugen Pechanec,
RecyclerView domyślnie używa DefaultItemAnimator. Więc dlaczego użyłeś tego kodu?
Athira Reddy
9

Dobrze więc trochę kopania i znalazłem te perełki z Bill Philips artykule naRecycleView

RecyclerView może zrobić więcej niż ListView, ale sama klasa RecyclerView ma mniej obowiązków niż ListView. Po wyjęciu z pudełka RecyclerView nie:

  • Umieść elementy na ekranie
  • Animuj widoki
  • Obsługuj wszystkie zdarzenia dotykowe oprócz przewijania

Wszystkie te rzeczy zostały wypieczone w ListView, ale RecyclerView używa klas współpracowników do wykonywania tych zadań.

Tworzone przez Ciebie ViewHolders są również bardziej rozbudowane. Są podklasą RecyclerView.ViewHolder, która ma wiele metod RecyclerView . ViewHolderswiedzieć, do jakiej pozycji są obecnie przypisane, a także jakie identyfikatory pozycji (jeśli je masz). W tym czasie ViewHolder został pasowany na rycerza. Kiedyś zadaniem ListView było zatrzymywanie całego widoku elementu i ViewHoldertrzymanie się tylko jego małych fragmentów.

Teraz ViewHolder zachowuje wszystko to w ViewHolder.itemView polu, które jest przypisane w konstruktorze ViewHolder dla Ciebie.

Mushtaq Jameel
źródło
4

Więcej z artykułu Billa Phillipa (przeczytaj go!), Ale pomyślałem, że ważne jest, aby zwrócić uwagę na następujące kwestie.

W ListView występowały niejasności dotyczące obsługi zdarzeń kliknięcia: czy poszczególne widoki powinny obsługiwać te zdarzenia, czy też ListView powinien obsługiwać je za pośrednictwem OnItemClickListener? Jednak w RecyclerView ViewHolder jest w wyraźnej pozycji, aby działać jako obiekt kontrolera na poziomie wiersza, który obsługuje tego rodzaju szczegóły.

Widzieliśmy wcześniej, że LayoutManager obsługiwał widoki pozycjonowania, a ItemAnimator zajmował się ich animowaniem. ViewHolder to ostatni element: jest odpowiedzialny za obsługę wszelkich zdarzeń, które występują na określonym elemencie wyświetlanym przez RecyclerView.

Jaison Brooks
źródło
2

Użyłem ListViewz Glide Image Loader, mając wzrost pamięci. Wtedy otrzymuje ListViewz RecyclerView. Jest to nie tylko trudniejsze w kodowaniu, ale także prowadzi do większego zużycia pamięci niż plik ListView. Przynajmniej w moim projekcie.

W innym ćwiczeniu użyłem złożonej listy z EditText's. W niektórych z nich metoda wprowadzania danych może się różnić, TextWatchermożna też zastosować. Gdybym użył a ViewHolder, jak mogłem zastąpić a TextWatcherpodczas przewijania? Więc użyłem a ListViewbez a ViewHolderi to działa.

CoolMind
źródło
Użyłem ListView bez ViewHolder i działa. okropny pomysł ... jak mogę zamienić TextWatchera podczas przewijania? nie trzeba go wymieniać ... po prostu TextWacher powinien umieścić dane w innym kontenerze po ponownym użyciu ... i można to zrobić bardzo łatwo
Selvin
@Selvin, dziękuję za twoją opinię. Teraz nie mogę edytować tego projektu. Na TextWatcherekranie było kilka sekund. Prawdopodobnie masz rację, ale nie mogę tego sprawdzić.
CoolMind
1

Ponownie wykorzystuje komórki podczas przewijania w górę / w dół - jest to możliwe dzięki zaimplementowaniu View Holder w adapterze listView, ale było to opcjonalne, podczas gdy w RecycleView jest to domyślny sposób pisania adaptera.

Oddziela listę od jej kontenera - dzięki czemu można łatwo umieścić elementy listy w czasie wykonywania w różnych kontenerach (linearLayout, gridLayout) za pomocą ustawienia LayoutManager.

Przykład:

mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//or
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
  • Animuje typowe akcje listy.

  • Animacje są oddzielane i delegowane do ItemAnimator.

Jest więcej informacji na temat RecyclerView, ale myślę, że te punkty są najważniejsze.

LayoutManager

i) LinearLayoutManager - który obsługuje zarówno listy pionowe, jak i poziome,

ii) StaggeredLayoutManager - który obsługuje Pinteresta jak listy schodkowe,

iii) GridLayoutManager - który obsługuje wyświetlanie siatek, jak widać w aplikacjach Galerii.

A najlepsze jest to, że możemy to wszystko robić dynamicznie, jak chcemy.

Keshav Gera
źródło
1

1. Zobacz posiadaczy

W ListView zdefiniowanie posiadaczy widoków było sugerowanym podejściem do przechowywania odwołań do widoków. Ale to nie był przymus. Chociaż nie robiąc tego, ListView użył pokazania nieaktualnych danych. Inna poważna wada polegająca na niestosowaniu uchwytów widoków może prowadzić do ciężkiej operacji wyszukiwania widoków za każdym razem za pomocą identyfikatorów. Co spowodowało opóźnienia w ListViews.

Ten problem został rozwiązany w RecylerView za pomocą klasy RecyclerView.ViewHolder. Jest to jedna z głównych różnic w RecyclerView i ListView. Podczas implementowania RecyclerView ta klasa służy do definiowania obiektu ViewHolder, który jest używany przez adapter do wiązania elementu ViewHolder z pozycją. Inną kwestią, na którą należy tutaj zwrócić uwagę, jest to, że podczas implementowania adaptera dla RecyclerView podanie elementu ViewHolder jest obowiązkowe. To sprawia, że ​​implementacja jest trochę skomplikowana, ale rozwiązuje problemy napotykane w ListView.

2. Menedżer układu

Mówiąc o ListViews, dostępny jest tylko jeden typ ListView, tj. Pionowy ListView. Nie można zaimplementować ListView z przewijaniem poziomym. Wiem, że istnieją sposoby na zaimplementowanie przewijania poziomego, ale wierz mi, że nie został zaprojektowany do tego celu.

Ale teraz, gdy spojrzymy na Android RecyclerView i ListView, mamy również obsługę kolekcji poziomych. W rzeczywistości obsługuje wiele typów list. Do obsługi wielu typów list używa klasy RecyclerView.LayoutManager. To jest coś nowego, czego ListView nie ma. RecyclerView obsługuje trzy typy predefiniowanych menedżerów układu:

LinearLayoutManager - jest to najczęściej używany menedżer układu w przypadku RecyclerView. Dzięki temu możemy tworzyć listy przewijania w poziomie i pionie. StaggeredGridLayoutManager - za pomocą tego menedżera układu możemy tworzyć listy schodkowe. Podobnie jak ekran Pinterest. GridLayoutManager - tego menedżera układu można używać do wyświetlania siatek, jak każda galeria obrazów.

3. Animator pozycji

Animacje na liście to zupełnie nowy wymiar, który ma nieskończone możliwości. W ListView jako takie nie ma specjalnych przepisów, za pomocą których można animować, dodawać lub usuwać elementy. Zamiast tego później, gdy Android ewoluował, ViewPropertyAnimator został zasugerowany przez Cheta Haase'a z Google w tym samouczku wideo dla animacji w ListView.

Z drugiej strony, porównując system Android RecyclerView z ListView, ma klasę RecyclerView.ItemAnimator do obsługi animacji. Dzięki tej klasie można zdefiniować niestandardowe animacje dla zdarzeń dodawania, usuwania i przenoszenia elementów. Zapewnia również DefaultItemAnimator, na wypadek, gdybyś nie potrzebował żadnych dostosowań.

4. Adapter

Adaptery ListView były proste w implementacji. Mieli główną metodę getView, w której zdarzała się cała magia. Gdzie widoki były związane z pozycją. Mieli też interesującą metodę registerDataSetObserver, w której można ustawić obserwatora bezpośrednio w adapterze. Ta funkcja jest również obecna w RecyclerView, ale jest do niej używana klasa RecyclerView.AdapterDataObserver. Ale zaletą ListView jest to, że obsługuje trzy domyślne implementacje adapterów:

ArrayAdapter CursorAdapter SimpleCursorAdapter Podczas gdy adapter RecyclerView ma wszystkie funkcje, które miały adaptery ListView, z wyjątkiem wbudowanej obsługi kursorów bazy danych i ArrayLists. W RecyclerView.Adapter od teraz musimy wykonać niestandardową implementację, aby dostarczyć dane do adaptera. Podobnie jak w przypadku BaseAdapter w przypadku ListViews. Chociaż jeśli chcesz dowiedzieć się więcej o implementacji adaptera RecyclerView, zapoznaj się z przykładem RecyclerView systemu Android.

5. Powiadamianie o zmianie danych

Podczas pracy z ListView, jeśli zestaw danych zostanie zmieniony, należy wywołać metodę notifyDataSetChanged adaptera bazowego, aby odświeżyć dane. Lub ustaw metodę setNotifyOnChange na true w przypadku, gdy chcesz automatycznie wywołać metodę notifyDataSetChanged. Ale w obu przypadkach wynik jest bardzo ciężki na liście. Zasadniczo odświeża widoki listy.

Ale wręcz przeciwnie w adapterze RecyclerView, jeśli zmienił się pojedynczy element lub zakres elementów, istnieją metody powiadamiania o zmianie. Są to odpowiednio notifyItemChanged i notifyItemRangeChanged i wiele innych, takich jak:

notifyItemInsterted notifyItemMoved notifyItemRangeInsterted notifyItemRangeRemoved I oczywiście ma oryginalną metodę odświeżania całej listy, tj. notifyDataSetChanged, która powiadamia zaadaptowany cały zestaw danych o zmianie.

6. Dekoracja przedmiotu

Aby wyświetlić niestandardowe separatory w ListView, można łatwo dodać te parametry w ListView XML:

XHTML android: divider = "@ android: color / transparent" android: dividerHeight = "5dp" 1 2 android: divider = "@ android: color / transparent" android: dividerHeight = "5dp" Interesującą częścią Android RecyclerView jest to, na razie nie wyświetla domyślnie podziału między elementami. Chociaż pracownicy Google celowo musieli to pominąć w celu dostosowania. Ale to znacznie zwiększa wysiłek programisty. Jeśli chcesz dodać separator między elementami, może być konieczne wykonanie niestandardowej implementacji przy użyciu klasy RecyclerView.ItemDecoration.

Możesz też zastosować hack, używając tego pliku z oficjalnych przykładów: DividerItemDecoration.java

7. OnItemTouchListener

Listviews miało prostą implementację do wykrywania kliknięć, np. Przy użyciu interfejsu AdapterView.OnItemClickListener.

Ale z drugiej strony interfejs RecyclerView.OnItemTouchListener służy do wykrywania zdarzeń dotykowych w systemie Android RecyclerView. Trochę komplikuje implementację, ale daje deweloperowi większą kontrolę nad przechwytywaniem zdarzeń dotykowych. Oficjalna dokumentacja stwierdza, że ​​może być przydatna do manipulacji gestami, ponieważ przechwytuje zdarzenie dotykowe przed dostarczeniem do RecyclerView.

Raviraj
źródło
1

RecyclerView został utworzony jako ulepszenie ListView, więc tak, możesz utworzyć załączoną listę z kontrolką ListView, ale użycie RecyclerView jest łatwiejsze, ponieważ:

  1. Ponownie wykorzystuje komórki podczas przewijania w górę / w dół : jest to możliwe dzięki zaimplementowaniu View Holder w adapterze ListView, ale było to opcjonalne, podczas gdy w RecycleView jest to domyślny sposób pisania adaptera.

  2. Oddziela listę od jej kontenera : dzięki czemu można łatwo umieścić elementy listy w czasie wykonywania w różnych kontenerach (linearLayout, gridLayout) za pomocą ustawienia LayoutManager.

mRecyclerView = (RecyclerView) findViewById (R.id.my_recycler_view); mRecyclerView.setLayoutManager (new LinearLayoutManager (this)); mRecyclerView.setLayoutManager (new GridLayoutManager (this, 2));

  1. Animuje wspólne akcje listy : animacje są oddzielane i delegowane do ItemAnimator. Jest więcej informacji na temat RecyclerView, ale myślę, że te punkty są najważniejsze.

Podsumowując, RecyclerView to bardziej elastyczna kontrolka do obsługi „danych listy”, która podąża za wzorcami delegowania problemów i pozostawia sobie tylko jedno zadanie - recykling elementów.

farzin borujerdi
źródło
0

Jeśli używasz RecycleView, najpierw potrzebujesz więcej wysiłku w konfiguracji. Musisz poświęcić więcej czasu na skonfigurowanie prostego elementu po kliknięciu, obramowaniu, zdarzeniu dotykowym i innych prostych rzeczach. Ale produkt końcowy będzie doskonały.

Więc decyzja należy do Ciebie. Proponuję, jeśli projektujesz prostą aplikację, taką jak ładowanie książki telefonicznej, w której wystarczy kliknięcie elementu, możesz zaimplementować widok listy. Ale jeśli projektujesz jak strona główna mediów społecznościowych z nieograniczonym przewijaniem. Kilka różnych dekoracji między przedmiotami, większa kontrola nad pojedynczym przedmiotem niż użycie widoku recyklingu.

Mahbubur Rahman Khan
źródło