Uvod

fragment

Fragment je modularni deo aktivnosti, koji ima svoj životni ciklus, prima sopstvene ulazne događaje, možete ga dodati ili ukloniti dok se aktivnost pokreće. Fragment objedinje View i logiku tako da se može jednostavno višekratno koristiti unutar jedne ili više različitih aktivnosti. U aktivnostima može biti više od jednog fragmenta tako da svaki fragment može da predstavlja neki View unutar jedne aktivnosti.
Prednost arhitekture koja koristi fragmenate je što nam fragmenti omogućavaju ponovnu upotrebu koda, sa jednostavnim postupkom pravljenja različitih prikaza za tablete (landscape) i mobilne uredjaje.

Navigacija izmedju fragmenata može biti definisana u sklopu aktivnosti koristeći samo FragmentManager, medjutim ništa nas ne sprečava da koristimo neki od sledećih pristupa:

  • TabLayout (tabovi)
  • Fragment Navigation Drawer (meni sa strane)
  • ViewPager (prebacivanje slajdovanjem izmedju fragmenata)

Komunikacija izmedju fragmenata se izvodi preko Aktivnosti, a za to se koristi “listener patern”

Fragmenat vs. Aktivnost

U aplikacijama koje koriste fragmente deo zaduženja aktivnosti se delegira u fragmente, pa bi prema toj podeli zaduženja koja ostaju u aktivnosti bi bila sledeća:

  • Da sadrži navigaciju do drugih aktivnosti putem intent-a ili navigacijske komponente (“NavigationDrawer”,“ViewPager”…)
  • Da skriva i prikazuje fragmenate (pomoću menadžera fragmenata)
  • Da prima podatake iz drugih aktivnosti (intent)
  • Da kumunicira sa fragmentima i posreduje komunikaciji između njih

Dok fragmenti preuzimaju obavezu da:

  • Prikazuju odgovarajući sadržaj
  • Event handling
  • Pokretanje network request-a
  • Preuzimanje i čuvanje podataka

NAPOMENA:
Fragment nije aktivnost pa samim tim nije podklasa klase Context, što znači da nema pristup globalnim informacijama o okruženju aplikacije. To znači da fragment ne može da koristi this za dobijanje context-a, već mora da koristi drugi objekat koji ima pristup context-u. Iz tog razloga u sklopu onCreateView() metode je prosledjen parametar LayoutInflater koji ima pristup kontekstu, te stoga ako nam je potreban context nega koristimo inflater.getContext().

Životni ciklus fragmenta direktno je pod uticajem životnog ciklusa aktivnosti. Kada je aktivnost pauzirana, onda su i svi su fragmenti u njoj pauzirani, a kada je aktivnost uništena, onda su i svi njeni fragmenti uništeni. Međutim, dok je aktivnost “živa”, možemo manipulisati sa svakim fragmentom nezavisno. Detaljan prikaz lifecycle fragmenta i aktivnosti možete pogledati ovde.

fragment lifecycle

NAPOMENA:
Uvek treba da pozovete ntklasu kada implementirate metode životnog ciklusa fragmenta. Npr. pri override metode onStart() u telu moramo da pozovemo super.onStart();

Kreiranje fragmenta

a) Postupno kreiranje od nule

Extendovanje fragment klase

Kreiranje fragmenta se sastoji iz kreiranja odgovarajuće klase zadužene za logiku i pridodajući joj odgovarajući layout. Klasa zadužena za logiku mora da extenduje neku od sledećih klasa:

  • Fragment je glavna klasa dok su ostale njegove podklase (pogledajte kako izgleda boilerplate kod koji generiše android studio).
  • DialogFragment – Fragment koji prikazuje prozor za dijalog, koji lebdi na vrhu prozora njegove aktivnosti. Ovo se obično koristi za prikazivanje dijaloga upozorenja, dijaloga za potvrdu ili za traženje informacija od korisnika u okviru bez potrebe za prebacivanjem na drugu aktivnost, dozvoljavajući korisniku da se vrati na prethodni fragment.
  • PreferenceFragmentCompat se koristi za kreiranje settings liste za našu aplikaciju odkle korisnici imaju mogućnost da promene funkcionalnost i ponašanje aplikacije. (pročitajte više u dokumentaciji).
  • ListFragment se koristi za prikazivanje liste nekih podataka i ima već implementiran event listener na clik nekog člana iz liste, tako da je potrebno samo da definišemo metod onListItemClick() (primer).

NAPOMENA:
Fragmenti nemaju metod findViewById().

Preko RootView-a

Ovaj način podrazumeva da prvo definišemo tzv. “rootView”, pa tek onda preko njega da koristimo findViewById():

getView()

Medjutim kada smo van metoda onCreate() i onCreateView() root view-a dobijamo sa metodom getView() (metoda getView() je dostupna čim ekstendujemo našu klasu sa klasom Fragment). Metoda getView() može da se pozove samo nakon kreiranja view-a, te je ne možemo koristiti unutar onCreate() ili onCreateView() metode, već samo u okviru onViewCreated() metode.

Primer

Povezivanje fragmenta sa njegovim layout-om

Da biste obezbedili layout za fragment, morate da implementirate “onCreateView()” metodu, koju Android poziva kada dođe vreme da fragment iscrta svoj layout. Implementacija ovog metoda mora da vrati prikaz koji je root layout vašeg fragmenta. Povezivanje fragment klase i njenog view-a se vrši korišćenjenm inflate() metode u sklopu lifecycle metode onCreateViewa:

Pogledajte više o postupku ubacivanja view-a iz xml-a u klasu “Layout inflation” u članku “Konvertovanje XML resursa u View objekat”.

NAPOMENA:
Ako je fragment podklasa ListFragment-a, kod njega se po default-u vraća ListView u metodi onCreateView(), tako da ne mora da se implementira deo vezan za povezivanje logike sa layout-om osim ako ne koristimo custom layout.

b) Kreiranje od pripremljnog boilerplate “Fragment(Blank)”

Ovaj pristup podrazumeva kreiranje fragmenta na osnovu androidovog template-a pod nazivom Fragment(Blank) u sklopu koga dolazi dosta boilerplate koda.

Factory statička metoda newInstance()

Ova metoda se koristi pri instanciranju fragmenta u okviru aktivnosi i omogućava jednostavno prosledjivanje parametara pri instanciranju fragmenta:

Sada u okviru fragmenta možemo da koristimo prosledjene parametre koristeći promenjive mParam1 i mParam2 a instanciranje Fragmenta u aktivnosti se vrši sa sledećim kodom:

Aktivnost

Custom Listener

U sklopu boilerplate koda dolazi deo vezan za CustomListener koji se koriste za prosledjivanje podataka iz fragmenta u aktvinost (drugi fragment).

Više o custom listener-ima pogledaj te u članku “Kreiranje custom listenera”. A ceo boilerplate kod možete da pogledate ovde.

×

Korišćenje fragmenta u aktivnostima

Fragmente u aktivnost možemo da dodamo na dva načina:

  1. Statično ubacivanje fragmenta direktno u layout aktivnosti
  2. Programirano ubacivanje fragmenta u postojeću ViewGroup-u

Napomena:
Aktvnost koja sadrži fragment mora da ekstenduje ili FragmentActivity ili njenu potklasu AppCompatActivity

Statično ubacivanje fragmenta direktno u layout aktivnosti

Statično ubacivanje fragmenta u aktivnost podrazumeva da se fragment ubaci u layout aktivnosti kao view.

Sa fragmentom ubačenim na ovaj način se manipuliše kao sa bilo kojim view-om.

Programirano ubacivanje fragmenta u aktivnost

Za programirano ubacivanje fragmenta u aktivnost je postupak sledeći:

a) Kreiranje fragment kontejnera u XML-u

Ako vaša aktivnost dozvoljava da se fragmenti uklone i zamene, trebalo bi da dodate početni fragment (tzv. fragmentKontejner) u “onCreate()”. Taj kontejner se koristi da u njega možemo kasnije da ubacimo neki drugi fragment.

b) Kreiranje fragmentManager-a

Fragment manager se instancira pozivajući metodu getSupportFragmentManager()

c) Kreiranje instance fragmenta

Instanciranje fragmenta koji hoćemo da ubacimo se vrši pozivanjem konstruktora fragmenta uz ključnu reč “new”:

PREPORUKA:
Iako je prethodno opisan postupak kreiranja instance fragmenta jednostavan preporuka je da se koristi tzv. newInstance pristup. Ovaj pristup nam omogućava da pri samom instanciranju fragmenta prosledimo podatke kao parametar metode. Factory metoda koja instacira fragment je statička metoda pod nazivom newInstance().

d) Izvršavanje neke od transakcija sa fragmentima (add, remove, replace)

Potoji API za rad sa fragmentima u aktivnosti (add, remove, or replace a fragment) i zove se FragmentTransaction. Instancu FragmentTransaction dobijamo koristeći fragmentManager.

Jedna od metoda koju može da izvrši FragmentTransaction je i add(). Ova metoda služi za ubacivanje našeg fragmenta u sklop nekog ViewGroup-a (kontejner). Taj ViewGroup se definiše kroz prvi parametar, dok se kroz drugi parametar definiše fragment koji dodajemo, a kroz treći parametar definišemo TAG koji će da obeleži dodati fragment (na osnovu taga kasnije možemo da ga targetiramo sa fragmentManager.findFragmentByTag(“TAGFRAGMENTA”);).

Da bi se klikom na “back” dugme vratili na prethodno stanje (tj. da ne bi smo zatvorili aktivnost što je podrazumevano) potrebno je da dadamo naš fragment na stack tzv. “backStack” sa metodom addToBackStack().

Po definisanju svih naredbi (može da ih bude više od jedne) je potrebno potvrditi akciju (commit-ovati), nakon čega će one biti i stvarno izvršene:

Akcije koje smo commit-ovali se ne izvršavaju odmah već ih stavljaju na čekanje za izvršavanje na glavnoj niti (main thread). Akcije će se izvršiti tek kada nit bude spremna. Pogledajte primere transakcija ovde.

NAPOMENA:
Targetiranje fragmenta u okviru aktivnost zavisi od toga kako je fragment ubačen u aktivnost.

a) Statički ubačen = targetiranje fragmenta preko ID-a

Ovaj pristup možemo koristiri kod statički embedovanog fragmenta direktno u XML aktivnosti i koji ima definisan Id:

b) Dinamički ubačen = targetiranje fragmenta preko Tag-a

Ovaj pristup koristimo kod dinamički embedovanih fragmenta, kada se kroz treći parametar metode definiše TAG preko koga ćemo da ga nadjemo:

×

Primer – ListFragment

×

Primer

U ovome primeru je prikazano definisanje početnog fragmenta u aktivnost. U prazan tag kontejnera se dodajemo novi view naš fragment.

Primer

U ovome primeru pozivajući metodu showFragmentA dolazi do zamene fragmenta

×

full fragment lifecycle

×

×

Back Stack

Stack je tip memorije u koji se smeštaju elementi jedan na drugi, tako da poslednji dodati element je na vrhu (analogija sa gomilom tanjira). Elementi se uklanjaju sa stacka obrnutim redosledom, tako što se poslednje dodati element uklanja prvi. U okviru Androida postoji stack u koji se smeštaju sve aktivnosti prema redosledu pozivanja. Pritiskanjem “back” dugmenta poslednja aktivnost sa stacka se briše. Medjutim u slučaju korišćenja fragmenta to nije defaultno ponašanje pa kada korisnik pritisne back sa stacka ne ukloni poslednje dodati fragment već cela aktivnost. To nije očekivano ponašanje te je potrebno je da tu funkcionalnost programer “ručno” doda.

backstack

addToBackStack

Da bi se i fragmenti ubacili na backStack potrebno je da se dodaju koristeći addToBackStack() metodu. Ovu metodu je potrebno dodati pre svakog commit-a. Tekst koji se prosledjuje je opcioni i koristi se ako kasnije želimo da prepoznamo tu transakciju, medjutim sasvim je ok da se prosledi i null kao parametar.

FragmentManager.OnBackStackChangedListener

Ako aplikacija sa promenom fragmenata treba da ažurira i druge elemente korisničkog interfejsa (npr. actionBar) to znači da bi trebalo se reaguje nakon promene backStack-a. U tom slučaju je potrebno da se iskoristi interfejs addOnBackStackChangedListener i da se definiše callback metoda onBackStackChanged() koja treba da izvrši akciju nakon okidanja dogadjaja

Primer kada aktivnost implementira interfejs

Primer kada se callback metoda onBackStackChanged() definie “on the fly”:

Podelite:

Ostavite komentar