Uvod

RecyclerView

Adapter je most između izvora podataka (Array objekat, List objekat…) i korisničkog interfejsa. Uloga adapter objekta (implementira Adapter interfejs) je da čita podatke iz različitih izvora podataka, i na osnovu njih popunjava View objekte članove nekog ViewGroup-a.
Do sada smo koristili ListView ali preporuka je da se umesto listView-a koristi RecyclerView, a naručito kada god imate kolekcije podataka čiji se elementi menjaju tokom izvršavanja aplikacije kao reakcija na aktivnost korisnika ili mrežnih dogadjaja. RecyclerView je naslednik ListView i GridView-a, i namenjen je da efikasno renderuje adapter-based view.
RecyclerView ima svoj adapter “RecyclerView.adapter” koji implementira ViewHolder patern, integriše “convertView” i ima pripremljene metode koji su zamena za sve što smo uradili kod “CustomArrayAdapter-a” a poboljšava efikasnost prikaza pri skrolovanju liste.

Postupak kreiranja RecyclerView.Adapter-a

a) Podaci za listu

U ovome primeru jedan član liste prihvata više podataka, stoga je potrebno napraviti klasu koja će da bude “modla” za kreiranje objekata koji čuvaju podatke jednog člana nekog AdapterView-a:

Definisali smo da se kroz konstruktor ubacuju podaci za svaki član liste, te stoga možemo da generišemo pocetnu listu podataka u okviru Aktivnosti (Fragmenta):

b) Kreiranje AdapterView-a

Potrebno je u sklopu layout-a Aktivnosti (fragmenta) definisati mesto gde će biti smeštena lista podataka. Ovaj deo je sličan kao kod običnog adaptera, stim što se kreira se umesto ListView koristi RecyclerView.

c) Kreiranje custom layout-a za jedan elementa liste

custom-adapter-row

Sada je potrebno napraviti custom layout, koji će da ih prikaže više podataka nemenjenih za jedan element liste. Ovaj deo nije bio potreban kod “običnog” adaptera ali je sada potreban zbog viška podataka, jer ne možemo da koristimo već predefinisane androidove layout-e koji prihvataju samo jedan podatak. U ovome primeru imamo za svaki row po tri podatka: slika i dva teksta.

NAPOMENA:
Klikom na row element RecyclerView-a se ne dešava očekivani “ripple” efekat. Da bi se takav efekat aktivirao potrebno je root View-u row layout-a dodati atribut: android:background=”?android:attr/selectableItemBackground”

Pogledajte ceo primer koda ovde.

d) Kreiranje Custom Adapter klase

Za kreiranja klase customAdaptera je potrebno da naša klasa ekstenduje RecyclerView.Adapter klasu. Da bi smo definisali koga tipa su podaci u adapter-u, potrebno je pre svega da unutar adaptera napravimo unutašnju statičnu ViewHolder klasu koja ekstenduje RecyclerView.ViewHolder klasu. Kada smo kreirali statičnu ViewHolder potrebnoje da unutar nje definišemo njenu spostvenu konstruktor metodu.

Sada možemo da okviru uglasitih zagrada ubacimo naziv našeg ViewHolder-a i tako definišemo koji tip prihvata adapter.

Tek nakon ovoga možemo da implementiramo sve metode koje zahteva RecyclerView.Adapter klasa, i da definišemo konstruktor koji prihvata ArrayList-u podataka kao parametar. Posle svega klasa bi trebalo ovako da izgleda:

Sada kada smo napravili kostur potrebno je definišemo i detalje.

Definisanje ViewHolder klase

Kao prvo potrebno je da u okviru ViewHolder klase targetiramo sve sub elemente iz example_item.XML layout-a:

Kreiranje instance ViewHolder-a

Prvo je potrebno izvršimo parsiranje row layout-a u View objekat, a to se vrši u okviru onCreateViewHolder() metode, pa se zatim taj objekat prosledi kao parametar konstruktoru nove ViewHolder instance:

Ubacivanje podataka u listu se vrši u sklopu onBindViewHolder() metode:

Definisanje veličine liste

Veličina liste se definiš u okviru getItemCount()

Cela Custom Adapter klasa sada izgleda ovako.

e) Ubacivanje RecyclerView-a u Aktivnost

Neophodne stvari koji definišu RecyclerView su:

  • View koji predstavlja RecylerView
  • RecyclerView.LayoutManager koji se koristi da definiše raspored elemenata u okviru RecyclerView-a (LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager)
  • Adapter koji se koristi za popunjavanje RecyclerView-a

NAPOMENA:
RecyclerView se uglavnom definiše tako da ne zavisi od child elemenata nego uglavnom od parent View-a u kome je smešten, te se njegova visina i šira generalno ne menje tokom vremena. Ali taj podatak moramo da naglasimo da android to ne bi svaki put proveravo kada ubacujemo novi ili izbacujemo već postojeći element. Iz tog razloga da bi poboljšali efiasnost RecyclerVie-a je dobro da definišemo naš RecyclerView kao da je fiksne veličine sa setHasFixedSize(true).

Pre svega je potrebno da definišemo polja koja će biti kasnije dostupna drugim delovima koda:

U sklopu onCreate() metode ćemo setovati napravljena polja:

Ceo kod koji se nalazi u Aktivnosti možete da pogledate ovde.

NAPOMENA
Ukoliko dodajemo ili uklanjamo element iz RecyclerView-a potrebno je posle svakog dodavanja obavestiti sistem da je došlo do promene pozivajući metodu notifyItemInserted(position):

Takodje treba i posle svakog uklanjanja postojećeg elelementa obavestiti sistem da je došlo do promene pozivaju’i metodu notifyItemRemoved(position):

Pa bi metode za ubacivanje i izbacivanje elemenata ovako izgledale:

Sve metode koje mogu da se korisite za obaveštavanje sisteme o premenama pogledajte ovde.

f) Definisanje click listener-a

Zajedno sa standardnim ListView-om stiže i onItemClick interfejs, medjutim toga nema kod RecyclerView-a stoga moramo da kreiramo naš interfejs i customClickListener (pogledaj kako se kreiraju customListener-i ovde).

Kreiranje novog interfejsa

Prvo je potrebno da u sklopu našeg Custom Adapter-a definišemo novi interfejs i jednu callback metodu:

Setter metoda

A zatim je potrebno da definišemo polje i setter metodu, čijim pozivanjem u Aktivnosti definišemo objekat koji osluškuje event:

Okidanje dogadjaja

Potrebno je “okinuti” dogadjaj klikom na neki element RecyclerView liste koji je definisan u ViewHolder klasi, a to ćemo uraditi tako što ćemo pozovati callback metodu našeg interfejsa:

Ovu metodu ćemo da pozovemo u trenutku kada se klikne na element “itemView” (predstavljen kao parametar konstruktorske metode). Iz tog razloga poziv metode će biti smešten u okviru onClick() metode:

Sigurno ste primetili da android studio prijavljuje grešku da ne može da nadje promenjivu listener pošto je naša klasa statična. Da bi smo napravili ovu promenjivu dostupnom, prosledićemo je kao parametar konstruktorskoj funkciji Custom ViewHolder klase. Ubacivanje listenera kao parametra klase je najlakše postići ako se u AndroidStudiu označi listener koji je problem i sa ALT + ENTER pozove pomoćni meni, gde se izabere opcija “Create parameter listener”, nakon čega će Android Studio odraditi sve sam.
Pa bi cela ViewHolder klasa sada ovako izgledala

NAPOMENA:
Pri svakom kliku na neki element liste je potrebno da znamo na koji element je kliknuto, to se jednostavno dobija koristeći metodu getAdapterPosition()

Definisanje objekta koji osluškuje i sadržaja callback metode

U okviru Aktivnosti se nadje objekat koji implementira interfejs a to je u našem slučaju instanca samog adaptera “mAdapter”. Zatim taj objekat poziva setter metodu setOnItemClickListener() da bi kroz prosledjeni parametar definisao objekat koji osluškuje event. U našem slučaju će to da bude anonimni objekat koji implementira interfejs “on the fly”. Akciju koja treba da se izvede nakon okidanja dogadjaja ćemo definisati tako što “pregazimo” (override) njegovu callback metodu onItemClick:

Pogledajte ceo kod Aktivnosti ovde.

Ovo je jednostavniji način i sve se definiše u okviru adapter klase. Prvo je potrebno da naša ViewHolder klasa implementira View.OnClickListener:

A nakon toga će AndroidStudio prijaviti grešku i zahtevati da se implementira i njegova callback metoda onClick(). U okviru ove metode se definiše akcija koja se dešava kada se okine dogadjaj tj. kada se klikne na neki član liste.

Da bi se definisao objekat koji osluškuje potrebno je da ga prosledimo kao parametar setOnClickListener() metodi u okviru ViewHolder konstruktora. U našem slučaju to je sam ViewHolder pa ćemo da prosledimo “this”:

Pa bi ceo ViewHolder ovako izgledao:

×

×

×

×

×

Method Description
notifyItemChanged(int pos) Notify that item at position has changed.
notifyItemInserted(int pos) Notify that item reflected at position has been newly inserted.
notifyItemRemoved(int pos) Notify that items previously located at position has been removed from the data set.
notifyDataSetChanged() Notify that the dataset has changed. Use only as last resort.

Podelite:

5 Responses to “Adapter za RecyclerView”

  1. Pocetnik sam u Android programiranju. Zanima me kako se menjaju svojstva view-a koji je prosledjen kao argument callback metodi onClick klase ExampleViewHolder? Npr, ovako mogu da promenim boju pozadine view.setBackgroundColor(0x4D00E640); ali npr ne mogu da pocesim text da bude bold? Npr view.setTypeface(null, Typeface.BOLD); ovo ne funkcionise, jer nad view objektom ne mogu da pozovem metodu setTypeFace. Hvala unapred.

    • Dragoljub

      Da li si targtirao TextView pa tek onda probao programirano da promeniš neko svojstvo?
      (kao npr. mTextView1 = itemView.findViewById(R.id.textView))

      • Matija Lukic

        Da, upravo tako sam i uspeo. Pravio sam gresku jer sam findViewById methodu pozivao nad v objektom onClick method-e, umesto nad itemView objektom. Hvala.

  2. Da bi ukapirao sta pise u ovom “uputstvu” moram da odgledam brdo tutrijala na netu, onda kada se vratim na tekst.. Postavlja se pitanje, cemu kad sam vec sve naucio.
    Ovo sve me podseca na neki veliki VIC iz delova namenjen samo za internu upotrebu u nekoj programerskoj firmi.
    Ne vidim smisao postojanja ovog teksta? Programeri koji to vec znaju jedini mogu da prate tekst, ostali, koji tek treba da nauce izgube nit.
    Deluje kao blog a nije, cini mi se da je “preslisavanje” programera na 3 godini studija koji je dobro spremio ispit.

    • Dragoljub

      Sajt je napravljen sa najboljim namerama (totalno neprofitabilan), i zamišljen kao pomoć programerima u vidu brzog podsetnka. Mogli ste da pročitate na početnoj strani da sadržaj sajta čine moje lične skripte koje su “malo” sredjene da bi dobile formu tutorijala, medjutim ja sam i za to “malo” sredjivanja (svakog od ovih stotinjak članaka) utrošio popriličnu količinu svog slobodnog vremena. Voleo bih da sada kada ste već naučili ovu oblast, i vi pomognete programersku zajednicu i napravite bolje “uputstvo”.
      Veliki pozdrav.

Ostavite komentar