Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
SVEUC ILIŠTE U ZAGREBU
FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA
ZAVRŠNI RAD br. 5137
Android aplikacija za upravljanje
rasporedom i rezultatima
sportskih natjecanja
Leon Hrnjak
Zagreb, lipanj 2017.
Zahvala tvrtki Five na savjetima i pomoći pri izradi ovog završnog rada.
Sadržaj
1. Uvod ...............................................................................................................1
2. Funkcionalnosti ............................................................................................2
2.1. Dionici .....................................................................................................2
2.2. Korisnički zahtjevi ...................................................................................2
2.3. Funkcionalni zahtjevi ..............................................................................4
2.4. Nefunkcionalni zahtjevi ...........................................................................5
3. Mapa dijaloga ................................................................................................6
4. Model podataka ........................................................................................... 14
4.1 Konceptualni model podataka ............................................................... 14
4.2 Opis konceptualnog modela podataka .................................................. 15
4.2 Opisi entiteta .......................................................................................... 16
5. Baza podataka ............................................................................................. 19
5.1 Firebase baza podataka ........................................................................ 19
5.2 Način spremanja podataka .................................................................... 20
5.3 Strukturiranje baze podataka ................................................................. 21
5.4 Struktura baze podataka ....................................................................... 23
5.5 Sigurnost Firebase baze podataka ........................................................ 26
6. Arhitektura i tehnologije ............................................................................. 27
6.1 Android .................................................................................................. 27
6.2 Aktivnost ................................................................................................ 27
6.3 Čista arhitektura .................................................................................... 28
6.3.1 Komponente čiste arhitekture ....................................................... 30
6.3.2 Prednosti čiste arhitekture ............................................................ 31
6.4 Injekcija ovisnosti ................................................................................... 31
6.5 RxJava .................................................................................................. 32
6.6 Primjer izvedbe arhitekture u aplikaciji .................................................. 34
7. Izvedba aplikacije........................................................................................ 37
7.1 Načini korištenja aplikacije .................................................................... 37
7.2 Praćenje turnira ..................................................................................... 37
7.3 Izrada novog turnira ............................................................................... 37
7.4 Strukturiranje turnira .............................................................................. 38
7.5 Pregled turnira ....................................................................................... 39
8. Zaključak ..................................................................................................... 40
9. Literatura ..................................................................................................... 41
10. Sažetak ...................................................................................................... 42
1
1. Uvod
Sport uključuje sve oblike fizičkih aktivnosti i igara koje ljudi izvršavaju iz
natjecateljskih razloga s ciljem održavanja i poboljšanja fizičkih sposobnosti i
vještina.
Bilo da se radi o spontano organiziranom nogometnom turniru u kvartu ili
velikom turniru s više sportova čije organiziranje i planiranje traje duže vremena,
javlja se potreba za praćenjem rasporeda događanja i rezultata. Na većini manjih
turnira potonje se rješava zapisivanjem rezultata na papir, lokalno na pametni
telefon ili prijenosno računalo. Navedena rješenja načelno nisu loša, ali su
nepraktična. Natjecatelji, ali i gledatelji bi htjeli u svakom trenutku znati točan
raspored događanja i trenutne rezultate što rezultira usmenom predajom
informacija, koje su često netočne, skupljanjem oko organizatora ili oglasne ploče.
Što napraviti u slučaju izmjene rasporeda ili ispravke netočnog rezultata? Kako to
sve organizirati ako se natjecanje održava na više lokacija? Upravo zbog navedenih
pitanja i problema javila se potreba za izradom aplikacije za praćenje rasporeda i
rezultata sportskih natjecanja.
Glavni cilj aplikacije je da služi kao centralno mjesto, na koje organizatori mogu
unositi raspored događaja i rezultate, a natjecatelji i gledatelji mogu pratiti taj isti
raspored i rezultate na svojim pametnim telefonima, neovisno o njihovoj lokaciji.
Također, s obzirom da se turniri često održavaju na više lokacija, događaje i
rezultate treba moći unositi više ljudi istovremeno sa više uređaja.
U ovom radu je opisana izvedba navedene aplikacije, od funkcionalnosti koje
vidi krajnji korisnik, do arhitekture, modela podataka i korištenih tehnologija.
2
2. Funkcionalnosti
2.1. Dionici
Anonimni korisnik
Prijavljeni korisnik
Moderator turnira
Administrator turnira
2.2. Korisnički zahtjevi
Korisnički zahtjevi su prikazani prema dionicima koji su organizirani
hijerarhijski, odnosno dionik uz svoje funkcionalnosti, ima i sve funkcionalnosti
dionika koji se hijerarhijski nalaze niže od njega. Administrator turnira se nalazi na
vrhu hijerarhije.
Anonimni korisnik
o Prilikom prvog pokretanja mogućnost odabira korištenja aplikacije kao
anonimni korisnik ili kao prijavljeni korisnik
o Naknadna prijava
o Praćenje bilo kojeg turnira za koji zna pristupni kod
o Praćenje više turnira odjednom
o Micanje turnira s liste praćenih turnira
o Pregled kategorija i nadolazećih događaja za pojedini turnir
o Detaljni pregled pojedine kategorije što uključuje trenutni poredak,
raspored i rezultate
Prijavljeni korisnik
o Mogućnost izrade vlastitog turnira što uključuje odabir:
Imena turnira
Loga turnira
Seta ikona i boje korisničkog sučelja
Pristupnog koda turnira
Kopiranje strukture turnira, što uključuje kategorije, discipline i
natjecatelje, od nekog drugog vlastitog turnira
3
o Izradom turnira, korisnik automatski postaje administrator tog turnira
Moderator turnira
o Dodavanje timova
o Dodavanje novih kategorija i disciplina
o Brisanje kategorija, disciplina i timova
o Dodavanje ligaške discipline uključuje odabir:
Imena discipline
Sporta
Ukoliko u sportu jedan tim igra protiv drugoga:
Definiranje bodova za pobjedu i remi
Ukoliko se radi o individualnim rezultatima
Definiranje vrste rezultata (bodovi ili vrijeme)
Vrednovanje rezultata (više je bolje ili manje je bolje)
Odabir datuma i vremena natjecanja
o Dodavanje eliminacijske discipline uključuje odabir:
Imena discipline
Sporta
Početne faze natjecanja
Završne faze natjecanja
Odigrava li se utakmica za treće mjesto
o Upravljanje ligaškom disciplinom
Dodavanje grupa
Raspoređivanje natjecatelja po grupama
Brisanje natjecatelja iz grupe
Dodavanje novih događaja što uključuje:
Odabir timova
Kolo u kojem se odigrava događaj
Datum i vrijeme događaja
Dodavanje rezultata događaja
o Upravljanje ligaškom disciplinom s individualnim rezultatima
Dodavanje novih rezultata
Brisanje rezultata
o Upravljanje eliminacijskog disciplinom
4
Dodavanje novih događaja kao i kod ligaške discipline
Dodavanje rezultata događaja
Brisanje događaja
Administrator turnira
o Brisanje turnira
o Dodavanje moderatora turnira
2.3. Funkcionalni zahtjevi
Upravljanje bazom podataka što uključuje stvaranje, pregledavanje,
uređivanje i brisanje:
o Turnira
o Kategorija i disciplina
o Timova
o Događaja
o Rezultata
Ime turnira i pristupni kod moraju sadržavati barem tri slova
Moguće je stvoriti turnir bez odabira loga
Timovi i discipline su poredani prema kategorijama kojima pripadaju
Brisanje kategorije rezultira brisanjem svih disciplina, timova i događaja
povezanih s tom kategorijom
Brisanje discipline rezultira brisanjem svih događaja povezanih s tom
disciplinom
Kod pregleda turnira događaji su poredani prema datumu i prikazuju se
samo nadolazeći događaji
Ligaške discipline
o Timovi su raspoređeni prema grupama, a moguće je da disciplina
ima samo jednu grupu
o Događaji su poredani prema kolima
o Brisanjem pojedine grupe, brišu se i svi događaji povezani s tom
grupom
o Prilikom dodavanja događaja timovi moraju biti različiti
Ligaške discipline s individualnim rezultatima
o Prikazuje se datum odvijanja natjecanja
5
o Rezultati mogu biti bodovi ili vremena, ovisno o postavkama
discipline
o Rezultati mogu biti poredani po principima „više je bolje“, ili „manje je
bolje“, ovisno o postavkama discipline
Eliminacijske discipline
o Događaji se dodaju klikom na kućicu u prikazu ždrijeba
o Moguće je dodati događaji s jednim timom, ukoliko tim u određenoj
fazi nema protivnika
o Moderatori i administratori moraju biti posebno oprezni kod
mijenjanja rezultata i događaja kako ne bi došlo do konflikta u višoj
fazi natjecanja
Sve akcije brisanja su popraćene porukom upozorenja kako bi se spriječilo
slučajno brisanje
Administrator ne može maknuti vlastiti turnir iz liste praćenja, niti promijeniti
svoj status u moderatora ili običnog korisnika
Brisanje turnira rezultira trajnim brisanjem svih podataka vezanih uz turnir
2.4. Nefunkcionalni zahtjevi
Aplikaciju je moguće koristiti i bez internetske veze, svi uneseni podaci će
biti sinkronizirani prilikom prvog spajanja na Internet
Iznimka prethodnog zahtjeva je izrada turnira za koju je potrebna
internetska veza
Više korisnika može unositi podatke u isto vrijeme
Baza podataka mora osigurati sigurnost podataka od neovlaštenih zapisa
neovisno o aplikaciji
o Za pojedini turnir podatke smiju zapisivati samo administratori i
moderatori koji se verificiraju preko jedinstvenog identifikatora kojeg
isporučuje Google
6
3. Mapa dijaloga
Slika 3.1 Prikaz početnog ekrana
7
Slika 3.2 Praćenje i izrada novog turnira
8
Slika 3.3 Prikaz liste turnira
9
Slika 3.4 Pregled turnira i ligaške discipline
10
Slika 3.5 Pregled eliminacijske discipline i ligaške discipline s individualnim
rezultatima
11
Slika 3.6 Uređivanje kategorija i stvaranje novih disciplina
12
Slika 3.7 Uređivanje ligaške discipline
13
Slika 3.8 Uređivanje eliminacijske discipline, dodavanje moderatora i brisanje
turnira
14
4. Model podataka
4.1 Konceptualni model podataka
Slika 4.1 ER model podataka
Slika 4.1 ER model podataka
15
4.2 Opis konceptualnog modela podataka
Entitet Tournament možemo smatrati glavnim entitetom u navedenom
modelu podataka. Svaki turnir ima definiran pristupni kod, ime, logo, set ikona i boju
sučelja. Set ikona i boja sučelja kao entiteti se ne nalaze u bazi podataka, već su
realizirani kao enumeracija unutar same aplikacije, a razlog za takav pristup će biti
objašnjen u kasnijim poglavljima. Isti slučaj vrijedi i za entitete Role, Sport, Round,
ResultType i Comparator. Svaki turnir je jedinstveno određen sa svojim pristupnim
kodom. Slika loga se fizički ne sprema u bazu podataka, već se sprema na server,
a u bazi podataka se čuva poveznica na samu sliku.
UserRole služi za spremanje uloga korisnika na pojedinom turniru. Trenutno
su podržane uloge regularni korisnik, moderator i administrator.
Za daljnje razumijevanje modela podataka, važno je napomenuti da je glavna
ideja aplikacije dati korisniku što više slobode u izradi vlastitoga turnira, kako bi se
pokrio što veći broj različitih formata natjecanja. Upravo zbog toga određeni entiteti
mogu se shvatiti na više načina.
Turnir se sastoji od nekoliko kategorija, koje služe kao grupacija za
natjecatelje i discipline. Disciplina predstavlja jedan dio natjecanja i može biti liga ili
eliminacija.
LeagueDiscipline ima definiran sport, vrstu rezultata, komparator, ime,
datum, bodove za pobjedu i remi te oznaku radi li se o ligi s duelima ili individualnim
rezultatima. U ovisnosti o sportu i vrsti rezultata, pojedina ligaška disciplina neće
imati spremljene sve navedene podatke. Ukoliko se radi o ligi s duelima, neće biti
potrebno definirati datum, vrstu rezultata i komparator, već samo bodove za pobjedu
i remi. Kod lige s individualnim rezultatima (kao što su utrke), vrsta rezultata
označava radi li se o bodovima ili vremenu, a komparator označava gleda li se veći
ili manji rezultat kao bolji. Također je potrebno definirati datum održavanja
natjecanja.
Group predstavlja jednu grupu unutar ligaške discipline. Pojedina grupa
može imati više natjecatelja, a pojedini natjecatelj može biti raspoređen u nekoliko
grupa, ali samo kada one pripadaju različitim disciplinama (primjer kada imamo više
ligaških disciplina unutar iste kategorije).
KnockoutDiscipline ima definiran sport, početnu i završnu rundu natjecanja
(četvrtfinale, polufinale, itd.), ime i oznaku igra li se utakmica za treće mjesto. Razlog
16
zašto uz početnu rundu se sprema i završna runda je da se pokrije slučaj gdje finale
nije nužno završna runda, što je česti slučaj kod kvalifikacija.
Competitor predstavlja jednog natjecatelja, koji može biti tim ili pojedinac. U
trenutnoj verziji aplikacije nema razlike između tima ili pojedinaca, ali u planovima
je dodati podršku za dodavanje pojedinaca timu.
Radi boljeg razumijevanja navedenih entiteta, zamislimo da imamo turnir na
kojem se igraju nogomet i košarka. Ekipe za nogomet i košarku su različite, odnosno
jedna ekipa igra ili nogomet ili košarku, ne oboje. Stoga ćemo napraviti dvije
kategorije, jednu za nogomet, jednu za košarku. Svakog kategoriji ćemo pridružiti
natjecatelje koji se natječu u njoj. Natjecanje u nogometu se sastoji od tri dijela,
kvalifikacija, grupne faze i eliminacijske faze. Unutar kategorije nogomet, stvaramo
tri discipline, eliminacijsku disciplinu za kvalifikacije i eliminacijsku fazu, te ligašku
disciplinu za grupnu fazu. Isto radimo i za košarku. Za slučaj da iste ekipe igraju
nogomet i košarku, mogli smo napraviti samo jednu kategoriju i unutar nje stvoriti
potrebne discipline za nogomet i košarku, no kao što je već napomenuto, na
krajnjem korisniku je da odluči kako će formatirati svoj turnir.
Event je entitet koji predstavlja duel (događaj) ili individualni rezultat. Ukoliko
je Event pridružen ligaškoj disciplini s duelima, imat će definiranu grupu u kojoj se
odigrava, prvog i drugog natjecatelja, njihove rezultate ukoliko je događaj već
odigran, datum, te kolo u kojem se događaj odigrava. Ukoliko je pridružen ligaškoj
disciplini s individualnim rezultatima, imat će definiranog prvog natjecatelja i njegov
rezultat. Kod eliminacijske discipline umjesto kola će biti definirana runda u kojoj se
događaj odigrava, te oznaka para u ždrijebu.
4.2 Opisi entiteta
Tournament – glavni entitet uz kojega su povezani svi podaci vezani za pojedini
turnir
AccessCode – pristupni kod turnira
Name – ime turnira
GuiColor – boja grafičkog korisničkog sučelja
IconSet – set ikona koje se koriste za pojedini turnir
LogoUrl – poveznica na sliku loga koja je spremljena na serveru
17
UserRole – predstavlja ulogu korisnika na pojedinom turniru
UserUid – jedinstveni identifikator korisnika
TournamentAccessCode – pristupni kod turnira za kojeg se sprema uloga
Role – korisnikova uloga
Category – kategorija na pojedinom turniru
TournamentAccessCode – pristupni kod turnira kojem pripada kategorija
Name – ime kategorije
Competitor – natjecatelj
CategoryId – kategorija kojoj pripada natjecatelj
Name – ime natjecatelja
LeagueDiscipline – ligaška disciplina
CategoryId – kategorija kojoj pripada disciplina
SportId – vrsta sporta
ResultTypeId – vrsta rezultata (bodovi ili vrijeme)
ComparatorId – označava koji rezultat se gleda kao bolji
Name – ime discipline
Date – datum odigravanja discipline (samo za discipline s individualnim
rezultatima)
PointsForWin – bodovi za pobjedu
PointsForDraw – bodovi za remi
IsSingleLeague – radi li se o disciplini s individualnim rezultatima
Group – grupa unutar ligaške discipline, sadrži popis natjecatelja koji se nalaze
unutar pojedine grupe
LeagueDisciplineId – ligaška disciplina kojoj pripada grupa
Name – naziv grupe
KnockoutDiscipline – eliminacijska disciplina
CategoryId – kategorija kojoj pripada disciplina
SportId – vrsta sporta
18
FirstRoundId – početna runda
FinalRoundId – završna runda
Name – ime discipline
ThirdPlaceMatch – odigrava li se utakmica za treće mjesto
Event – događaj ili individualni rezultat
KnockoutDisciplineId / GroupName – oznaka eliminacijske discipline ili
grupe kojoj događaj pripada (samo jedan od njih smije biti prisutan)
CompetitorOneId – prvi natjecatelj
CompetitorTwoId – drugi natjecatelj (ukoliko se radi o individualnom
rezultatu nije prisutan)
ScoreOne – rezultat prvog natjecatelja
ScoreTwo – rezultat drugog natjecatelja
RoundId – oznaka runde u kojoj se događaj odigrava (samo za
eliminacijske discipline)
IsSingle – označava radi li se o individualnom rezultatu ili duelu
IsPlayed – je li događaj već odigran i ima rezultat, ili će tek biti odigran
Date – datum odigravanja događaja (nije prisutan kod individualnih
rezultata)
KnockoutPair – par u ždrijebu (samo kod eliminacijskih disciplina)
Week – kolo (samo kod ligaških disciplina)
Sljedeći podaci se ne nalaze u bazi podataka, već su izvedeni kao enumeracija u
samom kodu.
IconSet – set ikona
Name – naziv seta ikona
Color – boja
Name – naziv boje
Role – uloga
Name – naziv uloge
19
Sport – set ikona
Name – naziv sporta
ResultType – vrsta rezultata
Type - vrsta
Round – faza natjecanja u eliminacijskoj disciplini
Name – naziv faze
Comparator – označava koji rezultat se gleda kao bolji
Name – naziv komparatora
5. Baza podataka
5.1 Firebase baza podataka
Firebase Database je NoSQL baza podataka u oblaku koja sve podatke
sprema u JSON formatu. Radi se o bazi podataka u stvarnom vremenu, što znači
da bilo kakva promjena u bazi na poslužitelju se odmah prenosi na uređaj.
Zahvaljujući tome aplikacije koje koriste Firebase bazu podataka rade brzo, jer se
podaci preuzimaju sa servera paralelno tijekom korištenja aplikacije, tako da kada
korisnik želi učitati određene podatke, oni se učitavaju direktno iz memorije uređaja,
a ne sa poslužitelja. Ukoliko korisnik izgubi vezu s internetom, podaci se spremaju
na uređaj i dostupni su cijelo vrijeme. Firebase prilikom instalacije aplikacije lokalno
stvori SQLite bazu podataka u koju zapisuje podatke koje dobije sa poslužitelja. Dok
je korisnik izvan mreže, sve operacije pisanja se spremaju lokalno i prilikom prvog
spajanja na Internet se sinkroniziraju s poslužiteljem.
Firebase baza podataka pruža fleksibilan jezik, temeljen na izrazima, za
definiranje pravila pristupa bazi i za definiranje strukture baze podataka pod
nazivom Firebase Realtime Database Security Rules. Detaljniji opis navedenog
jezika će biti prikazan u sljedećim poglavljima.
S obzirom da se radi o NoSQL bazi podataka, prisutne su drugačije
optimizacije i funkcionalnosti, od onih kod relacijskih baza podataka. API
(aplikacijsko programsko sučelje) Firebase baze podataka dozvoljava samo
20
operacije koje se mogu izvesti brzo, što omogućava izgradnju aplikacija koje može
koristiti velik broj ljudi, bez utjecaja na performanse.
5.2 Način spremanja podataka
Svi podaci u bazi podataka su spremljeni kao JSON objekti, što znači da
cijelu bazu podataka možemo smatrati jednim JSON stablom u oblaku. Dodavanjem
novog podatka u bazu, stvara se novi čvor u stablu, koji ima određeni ključ.
U konceptualnom modelu može se vidjeti da su svi ključevi tipa String, a
razlog tomu je korištenje Firebaseovog mehanizma za lokalno stvaranje globalno
jedinstvenih ključeva. Ključ koji generira Firebase sadrži 120 bitova informacije, od
čega prvih 48 bitova predstavlja vremensku oznaku koju slijedi 72 bita nasumičnih
znakova, čime se mogućnost da dvije osobe u istoj milisekundi stvore objekte s istim
ključevima svodi na minimum. Tako stvoreni ključ se zatim kodira koristeći base64
kod u ASCII znakove. Posebno je zanimljiva činjenica da se koristi prilagođeni
base64 kod, tako da se osigura kronološki poredak ključeva, ovisno o vremenskom
trenutku u kojem su stvoreni.
{
"tournament" : {
"ABCD1" : {
"info" : {
"guiColor" : 1,
"iconSet" : 1,
"logoUrl" : "url",
"name" : "Turnir 1"
}
}
}
}
Slika 5.1 Prikaz spremljenog podatka u Firebase bazi podataka
Na slici 5.1 možemo vidjeti kako su spremljeni osnovni podaci o pojedinom
turniru (entitet Tournament u konceptualnom modelu). Put u stablu do osnovnih
podataka o pojedinom turniru je sljedeći:
/tournament/$tournamentAccessCode/info,
pri čemu $tournamentAccessCode predstavlja pristupni kod pojedinog turnira.
21
5.3 Strukturiranje baze podataka
Prilikom strukturiranja NoSQL baze podataka, treba imati na umu da je
pristup nešto drugačiji nego kod relacijskih baza podataka. Za početak, moramo se
zapitati kako će se pristupati podacima. Pritom treba uzeti u obzir denormalizaciju,
koja je nužna, jer nam omogućava da podatke podijelimo na različite puteve, kako
bismo im efikasno mogli preuzimati.
{
"categories" : {
"c1" : {
"name" : "Nogomet",
"disciplines" : {
"d1" : {
...
},
"d2" : {
...
}
}
}
}
}
Slika 5.2 Prikaz loše strukture podataka
Na slici 5.2 prikazana je lista kategorija i sve discipline koje pripadaju
pojedinoj kategoriji. Zamislimo da trebamo dohvatiti popis s nazivima svih
kategorija. Jedno rješenje je da dohvatimo sve podatke s puta /categories.
Firebase dohvaća čitavo stablo s navedene adrese, odnosno dohvatiti će sve
kategorije i discipline po kategorijama. Što ako je disciplina jako puno i one u sebi
još sadrže događaje? Rezultat je dohvaćanje velike količine beskorisnih podataka,
kada nam u stvarnosti treba samo popis naziva. Rješenje je razdvojiti podatke na
odvojene puteve, odnosno denormalizacija. Svjesno unosimo redundanciju
podataka, kako bismo efikasnije mogli dohvaćati podatke.
Na slici 5.3 prikazana je struktura podataka koja nam omogućava efikasni
dohvat liste svih disciplina. Bitno je primijetiti da se ključ od pojedine discipline sada
nalazi na dva mjesta. Denormalizacijom smo „izravnali“ strukturu podataka,
odnosno smanjili dubinu stabla što je poželjno kod NoSQL baza podataka.
22
{
"disciplines" : {
"d1" : {
"name" : "Nogomet",
}
},
"categories" : {
"d1" : {
"c1" : {
...
},
"c2" : {
...
}
}
}
}
Slika 5.3 Prikaz denormalizacije
N-N veze su još jedan primjer gdje je nužno uvesti redundanciju podataka,
kako bismo sačuvali efikasnost pri dohvaćanju podataka. Jedan takav primjer su
grupe i natjecatelji, gdje grupa može imati više natjecatelja, a natjecatelj se može
nalaziti u više grupa. S obzirom da nas zanima samo koji se natjecatelji nalaze u
pojedinoj grupi (grupe u kojima se nalazi natjecatelj nam nisu potrebne) bazu
strukturiramo kao na slici 5.4.
{
"groups" : {
"A" : {
"competitors" : {
"comp1" : true,
"comp2" : true
}
}
},
"competitors" : {
"comp1" : {
"name" : "Competitor 1"
},
"comp2" : {
"name" : "Competitor 2"
}
}
}
Slika 5.4 Prikaz N-N veze
23
Na putu /groups/A/competitors dodajemo ključeve od natjecatelja koji pripadaju
navedenoj grupi, konkretna vrijednost nije bitna, bitno je samo da ključ postoji. S
ovakvim pristupom možemo elegantno dohvatiti natjecatelje koji pripadaju pojedinoj
grupi, bez da pretražujemo sve dostupne natjecatelje.
5.4 Struktura baze podataka
{
"tournament" : {
"$tournament_access_code" : {
"competitors" : {
"$category_id" : {
"$competitor_id" : {
"name" : String,
},
...
},
...
},
"categories" : {
"$category_id" : {
"name": String
},
...
},
"groups" : {
"$category_id" : {
"$discipline_id" : {
"$group_name" : {
"competitors" : {
"$competitor_id" : Boolean,
...
},
"name" : String
},
...
},
...
},
...
},
24
"info" : {
"guiColor" : Integer,
"iconSet" : Integer,
"logoUrl" : String,
"name" : String
},
"knockout_disciplines" : {
"$category_id" : {
"$discipline_id" : {
"name" : String,
"firstRound" : Integer,
"finalRound" : Integer,
"sport" : Integer,
"thirdPlaceMatch" : Boolean
},
...
},
...
},
"league_disciplines" : {
"$category_id" : {
"$discipline_id" : {
"name" : String,
"pointsForWin" : Integer,
"pointsFowDraw" : Integer,
"resultType" : Integer,
"sport" : Integer,
"date" : Long,
"isSingleLeague" : Boolean
},
...
},
...
},
"events" : {
"$category_id" : {
"$discipline_id" : {
/* Ukoliko se radi o ligaškoj disciplini postoji još
dodatni čvor "$group_name" */
"$event_id" : {
"competitorOneId" : String,
"competitorTwoId" : String,
"date" : Long,
"isPlayed" : Boolean,
"isSingle" : Boolean,
"scoreOne" : Float,
"scoreTwo" : Float,
"knockoutPair" : Integer,
25
"round" : Integer,
"week" : Integer
}
},
...
},
...
},
"user_roles" : {
"$user_uid" : {
"displayName" : String,
"role" : Integer
},
...
}
}
},
"tournament_list" : {
"$tournament_access_code" : Boolean,
...
},
"user_following_list" : {
"$user_uid" : {
"$tournament_access_code" : Boolean,
...
}
}
} Slika 5.5 Prikaz strukture cijele baze podataka
Na slici 5.5 koja se proteže kroz nekoliko stranica nalazi se prikaz strukture
baze podataka korištene u aplikaciji. Čvorovi označeni sa znakom $ predstavljaju
polja čija vrijednost se mijenja ovisno o ključevima pojedinih JSON objekata.
Glavni čvor svakog turnira je „tournament“. Popis svih turnira nalazi se u
čvoru „tournament_list“, a popis turnira koje prati pojedini korisnik nalazi se u čvoru
„user_following_list“.
Unutar čvora „tournament“ nalazi se čvor „info“ koji sadrži osnovne
informacije o turniru. Čvor „competitors“ sprema natjecatelje prema kategorijama,
„categories“ sprema popis kategorija, „knockout_disciplines“ i „league_disciplines“
sprema popis disciplina prema kategorijama, „groups“ sprema popis grupa prema
disciplinama i kategorijama kojima te discipline pripadaju, a isti put ima i čvor
„events“ unutar kojeg su spremljeni podaci o događajima. Čvor „user_roles“ sprema
uloge korisnika unutar pojedinog turnira.
26
Jedan od razloga zašto se popis ikona, boja, rundi i ostalih tablica koje su
ostvarene kao enumeracije u samom kodu aplikacije, ne nalazi u bazi podataka, je
činjenica da se gotovo sav posao vezan uz spajanje povezanih podataka obavlja
unutar same aplikacije. Firebase pruža sučelje koje može dohvatiti „čiste“ podatke,
odnosno dobiveni objekti će sadržavati isključivo id povezanog objekta, a na klijentu
je da poveže id s konkretnim objektom. Iz optimizacijskih razloga je odlučeno da se
manje tablice realiziraju kao enumeracije, kako bi se smanjio broj potrebnih upita i
spajanja podataka. Ukoliko će se naknadno raditi Web aplikacija, ova stavka će se
ponovno razmotriti.
5.5 Sigurnost Firebase baze podataka
Već je ranije spomenuto da Firebase pruža jezik kojim se mogu definirati
pravila pristupa pojedinim dijelovima stabla baze podataka. Pravila rade na način,
da kada se korisniku da pravo pristupa određenom čvoru, on dobiva pravo pristupa
za cijelo stablo koje slijedi iz tog čvora i to pravo nije moguće ukinuti u dubljim
čvorovima.
Navedena pravila rade u paru sa sustavom autorizacije od Firebasea, stoga
se on koristi prijavu korisnika. Nakon što korisnik odabere Googleov račun s kojim
se želi prijaviti, unutar Firebasea se zapiše njegov jedinstveni identifikator. Taj isti
identifikator se koristi prilikom spremanja uloga korisnika, tako da je vrlo
jednostavno odrediti ima li korisnik administratorska ili moderatorska prava za
pojedini turnir.
"tournament":{
"$tournament_id":{
"competitors":{
".write": "root.child('tournament/'
+ $tournament_id
+ '/user_roles/'
+ auth.uid
+ '/role').val() > 1"
},
...
} Slika 5.6 Prikaz definiranih pravila za pristup čvoru „competitors“
Na slici 5.6 nalazi se prikaz definiranih pravila za čvor „competitors“. Daje se
pravo pisanja unutar tog čvora korisnicima koji na putu
27
/tournament/$tournament_id/user_roles/$uid/role
imaju vrijednost veću od 1, što označava da se radi o administratoru ili moderatoru
(pri čemu, vrijednost uid dobavlja Firebase prilikom slanja podataka). Na isti način
su definirana pravila i za ostale čvorove. Time se osigurava da nitko ne može raditi
zapise na navedenim lokacijama, ukoliko nije prijavljen s Google računom
administratora ili moderatora.
6. Arhitektura i tehnologije
6.1 Android
Android je mobilni operacijski sustav razvijen od strane Googlea. Baziran je
na Linux kernelu s namjenom prvenstveno za uređaje s ekranima osjetljivima na
dodir kao što su mobiteli i tableti, a s vremenom se je proširio i na televizije, aute,
pametne satove i brojne druge uređaje. Danas je Android uvjerljivo
najrasprostranjenija mobilna platforma, a njegova popularnost i dalje raste.
Trenutno najnovija verzija je 7.1 s kodnim imenom Nougat, a minimalna podržana
verzija za pokretanje aplikacije, koja je tema ovog završnog rada, je 4.4 KitKat, čime
je prema Googleovim podacima pokriveno 73.9% uređaja.
6.2 Aktivnost
Aktivnost (engl. Activity) je jedna od temeljnih komponenti za izgradnju
Android aplikacija. Sav kod se izvodi unutar aktivnosti, koje pokreće sustav Android,
pozivajući određenu callback metodu koja odgovara određenoj fazi životnog ciklusa
aktivnosti.
Aktivnost predstavlja početnu točku u interakciji aplikacije s korisnikom,
pružajući prozor u kojemu aplikacija prikazuje grafičko sučelje. Tipično jedna
aktivnost, predstavlja jedan ekran u aplikaciji. Većina aplikacija se sastoji od više
aktivnosti, od kojih je jedna aktivnost glavna (engl. Main activity) koja se prva
pokreće s aplikacijom. Zatim se aktivnosti međusobno pozivaju i time izvode razne
akcije. [1]
Za razumijevanje rada aplikacije, nužno je dobro poznavati životni ciklus
aktivnosti, koji je prikazan na slici 6.1.
28
Slika 6.1 Prikaz životnog ciklusa aktivnosti
Prilikom prvog pokretanja aktivnosti pokreće se metoda onCreate(), u kojoj
se mora pozvati metoda setContentView() kojom definiramo izgled grafičkog sučelja
aktivnosti. Nakon što završi metoda onCreate() pokreće se metoda onStart() i
aktivnost postaje vidljiva korisniku, no ona još nije interaktivna. Prije nego što
aktivnost postane interaktivna pozive se onResume(). U ovom trenutku aktivnost se
nalazi na vrhu stoga aktivnosti i prihvaća korisnikove akcije. Kada aktivnost izgubi
fokus, poziva se onPause(). Ukoliko je aktivnost i dalje vidljiva te dobije ponovno
fokus, poziva se onResume(). Ako nije više vidljiva, što se može dogoditi ako se
aktivnost uništava, stvara se nova aktivnost, ili je stara aktivnost ušla u onResume(),
poziva se onStop(). Nakon što se zaustavljena aktivnost ponovno pokreće poziva
se onRestart(), nakon kojeg se poziva onStart(). Ukoliko se aktivnost uništava
poziva se onDestroy() čime se oslobađaju svi resursi zauzeti tom aktivnošću.
6.3 Čista arhitektura
Jedan od najvećih problema s kojim se programer može susresti tijekom
razvoja Android aplikacije je dizajniranje sustava. Poveća kompleksnost Androida u
29
kombinaciji s lošim odlukama tijekom razvoja dovode do situacije u kojoj imamo
aplikaciju koja je krhka, teško nadogradiva te gotova nemoguća za testiranje. Kod
tako dizajniranog sustava, kada treba dodavati nove mogućnosti koje nisu bile
planirane u početku, često je lakše i bolje napraviti cijelu aplikaciju „od nule“, nego
pokušati prilagoditi loše dizajniranu aplikaciju.
Zbog navedenih razloga bitno je od početka jasno definirati arhitekturu koja
će se koristiti prilikom razvoja aplikacije. Temeljem tuđih iskustava i savjeta, u ovom
završnom radu korištena je Čista arhitektura (engl. Clean Architecture).
Slika 6.2 Čista arhitektura
Čista arhitektura temelji se na 3 osnovna svojstva.
Prvo je pravilo ovisnosti, koje kaže da vanjski slojevi trebaju ovisiti o
unutarnjim slojevima, a unutarnji slojevi ne smiju znati ništa o vanjskim slojevima.
Na slici 6.2 navedeno pravilo prikazano je s 3 strelice koje su usmjerene od vanjskih
slojeva prema unutarnjima.
Drugo svojstvo je apstrakcija, odnosno kako se krećemo prema centru
dijagrama, apstrakcija se povećava. Vanjski slojevi sadrže implementacijske
dijelove, a unutarnji slojevi poslovnu logiku. Kao primjer možemo uzeti dohvat
podataka o turniru. U unutarnjem sloju ćemo definirati apstraktno sučelje za dohvat
podataka, koje zatim poslovna logika može slobodno koristiti za prikaz podataka
korisniku, bez da išta zna o detaljima implementacije tog sučelja, a u vanjskom sloju
ćemo implementirati to sučelje ovisno o tome želimo li dohvaćati podatke lokalno, s
30
poslužitelja ili s neke treće lokacije. Takvo ponašanje je poželjno zato što nam
omogućava da promijenimo implementaciju apstraktnog sučelja bez ikakvog
utjecaja na poslovnu logiku.
Posljednje svojstvo je komunikacija između slojeva. Zamislimo situaciju u
kojoj dohvaćamo podatak s interneta, obrađujemo ga i želimo ga prikazati korisniku.
Ako pogledamo dijagram na slici 6.2 možemo vidjeti da su internet i prikaz podataka
implementacijski detalji, a poslovna logika sredina između njih. Pravilo ovisnosti
nam ne dopušta da podatak dohvatimo s interneta i pošaljemo ga poslovnoj logici
koja će ga zatim poslati na ekran. Desno od dijagrama nalazi se rješenje našeg
problema, ulazna i izlazna sučelja, koja ćemo koristiti za komunikaciju među
slojevima. Zeleni sloj će komunicirati s crvenim slojem preko ulaznog sučelja
definiranog u crvenom sloju. S obzirom da zeleni sloj ovisi o crvenom sloju on ima
referencu na njegovo sučelje i može jednostavno pozvati metodu tog sučelja. Objekt
crvenog sloja je zadužen za implementaciju tog sučelja. Problem nastaje kada
crveni sloj treba poslati podatak zelenom sloju, bez da ovisi o njemu. Rješenje je
izlazno sučelje preko kojega crveni sloj može poslati podatak, bez da zna kome ga
šalje, što je u redu jer time ne postoji ovisnost o vanjskom sloju. Sada objekt zelenog
sloja može implementirati to sučelje i uspostaviti komunikaciju s crvenim slojem. [2],
[3]
6.3.1 Komponente čiste arhitekture
Preostaje nam još upoznati se sa komponentama u pojedinim slojevima čiste
arhitekture.
Počevši od unutarnjeg sloja, entiteti odnosno domenski modeli predstavljaju
glavnu funkcionalnost aplikacije. To su objekti najviše razine apstrakcije, nad kojima
se obavlja poslovna logika.
Scenariji korištenja (engl. Use Cases) su komponente koje sadrže poslovnu
logiku aplikacije. Pojedini scenarij korištenja obavlja jednu specifičnu radnju, čime
se zadovoljava načelo jedinstvene odgovornosti. Dobar scenarij korištenja može se
opisati jednostavnom rečenicom koja opisuje akciju koja se obavlja, npr. stvori novi
turnir.
Repozitoriji sadrže izlazna sučelja za scenarije korištenja koji ih koriste za
pristup i spremanje podataka. Konkretan način dohvata i spremanja podataka, bilo
31
iz baze podataka, bilo s interneta ili nekog trećeg izvora, je definiran u višim
slojevima.
Srednji sloj predstavlja poveznicu između konkretnih implementacijskih
detalja i poslovne logike. Prezenteri su zaduženi za upravljanje korisnikovim
interakcijama s aplikacijom. Pozivaju odgovarajuću poslovnu logiku te dobiveni
rezultat šalju grafičkom sučelju na prikaz. Uz prezentere je vrijedno spomenuti
konvertere koji pretvaraju modele unutarnjih slojeva u modele vanjskih slojeva.
Tipični primjer korištenja konvertera je slanje podataka grafičkom sučelju, gdje se
šalju modeli pogleda (engl. View Model), a ne modeli koji se koriste za poslovnu
logiku.
Uređaj (engl. Device) se nalazi u vanjskom sloju čiste arhitekture. On sadrži
implementacije raznih senzora, alarma, notifikacija i drugih komponentni direktno
povezanih s Androidom. Iz navedenog se jasno vidi da se ovdje radi o konkretnim
implementacijama, odnosno najnižoj razini apstrakcije.
Baza podataka i API su također komponente vanjskog sloja, a konkretne
implementacije repozitorija se nalaze upravo unutar ovih komponenti.
Posljednja komponenta koja nam preostaje je korisničko sučelje unutar kojeg
se stavljaju aktivnosti, fragmenti, adapteri i ostali razredi povezani s korisničkim
sučeljem. [4]
6.3.2 Prednosti čiste arhitekture
Nakon upoznavanja sa osnovama čiste arhitekture, postaje jasno da ona
omogućava pisanje koda koji je neovisan o radnim okvirima, korisničkom sučelju,
bazi podataka i API-ju. Ona nam omogućava lagano ispitivanje koda i pronalaženje
grešaka jer su komponente međusobno odvojeno, a samim time i lagano dodavanje
novih mogućnosti. Iako se radi o vrlo kompliciranom pristupu razvoju, dugoročno se
itekako isplati.
6.4 Injekcija ovisnosti
Kako bi se očuvalo načelo jedinstvene odgovornosti i dodatno smanjile
ovisnosti želimo lokalizirati odgovornost za stvaranje novih objekata koristeći
obrazac tvornice. Tvornice su zadužene za stvaranje gotovo svih objekata, osim
32
onih za koje je zadužen sam Android, poput aktivnosti i fragmenata. Svaki objekt
stvoren u tvornici ima životni vijek, odnosno on može živjeti paralelno s aplikacijom
ili ga možemo stvarati kada ga neka komponenta zatreba. Objekti mogu sadržavati
i druge komponente koje su im potrebne za rad. Jednostavno rješenje bi bilo da
objekt sam stvori sve potrebne komponente, ali time se stvara ovisnost objekta o
njegovim komponentama, stoga želimo tu odgovornost prebaciti na tvornicu. Za tu
potrebu koristimo injekciju ovisnosti, odnosno sve dodatne komponente koje su
potrebne objektu za rad, dodajemo u njegov konstruktor i prepuštamo tvornici da ih
stvori i preda referencu objektu prilikom stvaranja istog. Kako ne bismo ručno morali
obavljati sav posao oko tvornica, koristi se biblioteka Dagger2.
Kako bismo definirali kako injekcija ovisnosti treba raditi, moramo stvoriti
module i komponente. Moduli definiraju dobavljače (engl. Provider) koji su zaduženi
za dobavljanje pojedinih objekata. Komponente služe kao sučelja pomoću kojih
Dagger stvara kod koji će obavljati injekciju ovisnosti umjesto nas.
6.5 RxJava
RxJava je knjižnica koja omogućava funkcionalno reaktivno programiranje u
javi. Osnovne komponente RxJave su Observables i Subscribers. Observable
emitira podatke koje zatim koristi Subscriber. RxJava je posebno zanimljiva kod
razvoja Android aplikacija jer omogućava elegantan način za pisanje asinkronih
programa baziranih na događajima.
Na slici 6.3 prikazan je klasični način obavljanja asinkronih radnji. Želimo
dohvatiti podatke o pojedinom turniru. Znamo da ne smijemo izvoditi radnje s
internetom na glavnoj dretvi, a isto tako ne smijemo osvježavati korisničko sučelje
iz pozadinske dretve. Stoga stvaramo AyncTask koji će u metodi doInBackground()
obaviti radnju koja traje neko vrijeme, u ovom slučaju dohvat podataka o turniru, a
u onPostExecute() ćemo dobiveni rezultat prikazati na ekran. Navedeno rješenje je
nečitko, nije jednostavno za upravljanje pogreškama i može izazvati curenje
memorije (engl. Memory leak) zato što dretva koja se izvodi u pozadini čuva
referencu na vanjski kontekst.
33
private class GetTournamentInfo extends AsyncTask<Void, Void, Tournament>{
private final String accessCode;
public GetTournamentInfo(final String accessCode){
this.accessCode = accessCode;
}
@Override
protected Tournament doInBackground(Void...voids params){
return tournamentApi.getTournamentInfo(accessCode);
}
@Override
protected void onPostExecute(final Tournament tournament){
displayTournamentInfo(tournament);
}
}
...
new GetTournamentInfo("ABCD").execute();
...
Slika 6.3 Asinkrona radnja pomoću AsyncTaska
Na slici 6.4 prikazano je rješenje istog problema koristeći RxJavu.
Pozivanjem tournamentApi.getTournamentInfo() stvara se novi Observable za koji
smo definirali na kojoj dretvi ga želimo promatrati i na kojoj dretvi se želimo
pretplatiti. Objekte subscribeScheduler i observeScheduler dohvaćamo pomoću
injekcije ovisnosti. Još jedna zgodna stavka RxJave je manipulacija emitiranog toka,
koju možemo izvoditi pomoću operatora map(), flatMap(), filter() itd. Dobiveno
rješenje je vrlo elegantno. Kako bismo riješili problem mogućeg curenja memorije,
prilikom pokretanja aktivnosti stvaramo objekt tipa CompositeDisposable u kojeg
ćemo spremati sve pretplate. Nakon što aktivnost završi sa radom, uništavamo sve
pretplate koje se nisu stigle izvršiti, pozivajući compositeDisposable.dispose(), što
omogućava oslobađanje svih resursa zauzetih od strane trenutne aktivnosti.
34
...
compositeDisposable.add(
tournamentApi.getTournamentInfo(accessCode)
.subscribeOn(subscribeScheduler)
.observeOn(observeScheduler)
.subscribe(this::displayTournamentInfo,
this::logError));
...
private CompositeDisposable compositeDisposable=
new CompositeDisposable();
@Override
public void onResume(){
compositeDisposable = new CompositeDisposable();
}
@Override
public void onPause(){
if(!compositeDisposable.isDisposed()){
compositeDisposable.dispose();
}
} Slika 6.4 Asinkrona radnja pomoću RxJave
6.6 Primjer izvedbe arhitekture u aplikaciji
Kao primjer izvedbe arhitekture koristiti će se ekran za prikaz ligaške
discipline s individualnim rezultatima. Na slici 6.3 možemo vidjeti prikaz osnovne
strukture pojedinog ekrana.
Slika 6.5 Prikaz razreda pojedinog ekrana
Za početak, svaki ekran je organiziran prema MVP (Model-View-Presenter)
oblikovnom obrascu. Svaki razred, osim modela, mora imati svoje sučelje koje
implementira. Unutar sučelja SingleLeagueOverviewContract nalaze se sučelja za
35
pogled (engl. View) i prezenter (engl. Presenter). Također, vrijedi spomenuti da se
u aplikaciji primjenjuje Null Object obrazac, što znači da se nigdje ne vraća null
vrijednost, već se za svaki razred definira EmptyObject koji ne sadrži nikakvu logiku,
već samo služi kao dodatna razina sigurnosti unutar aplikacije. Aktivnost predstavlja
osnovnu komponentu svakog ekrana. U našoj arhitekturi svaka aktivnost sadrži
barem jedan fragment, koji ima ulogu pogleda. Za navigaciju fragmentima i
aktivnostima zadužen je usmjerivač (engl. Router). Svaki pogled ima definiran svoj
prezenter i model pogleda (engl. View Model). Prezenter je zadužen za obavljanje
poslovne logike, a rezultat šalje pogledu u obliku modela pogleda, kojeg generira
maper (engl. Mapper). S obzirom da se prezenter nalazi u sloju koji je dublje od
sloja pogleda, on ne može njemu direktno slati podatke. Zato svaki pogled ima
vlastito sučelje koje implementira, koje onda prezenter poziva kako bi poslao
podatke u viši sloj. Valja primijetiti da prezenter ne zna kome točno šalje podatke,
jer nema referencu na pogled. Za razliku od toga, pogled ima referencu na prezenter
i šalje mu podatke direktno preko sučelja.
Prezenter podatke dohvaća preko scenarija korištenja (engl. Use Case), koji
pozivaju repozitorije (engl. Repository). Prezenter ne zna konkretni izvor podataka,
što je i poželjno, jer time sprječavamo stvaranje ovisnosti. Repozitorij odabirom
određenih klijenata (engl. Client) bira izvor ili odredište podataka. Ukoliko želimo
implementirati čuvanje dohvaćenih podataka u memoriji (engl. Caching), repozitorij
će biti zadužen za spremanje dohvaćenih podataka i kasnije učitavanje navedenih
podataka iz memorije, a ne ponovno dohvaćanje s interneta. Klijent je zadužen za
pretvorbu domenskih modela u API modele i obrnuto te pozivanje API-ja.
Pogledajmo sada kako izgleda komunikacija među komponentama na
konkretnom primjeru. Nakon što sustav Android stvori aktivnost, unutar metode
onCreate() poziva se metoda rutera, showSingleLeagueOverviewScreen(), čime se
stvara i prikazuje fragment SingleLeagueOverviewFragment. Nakon stvaranja
fragmenta, u metodi onResume() poziva se metoda prezentera, activate(). Unutar
metode activate() u prezenteru, kreće dohvat potrebnih podataka, a kao primjer
ćemo pogledati dohvat rezultata za traženu disciplinu. Prezenter poziva metodu
execute(), scenarija korištenja GetScoresForGroupUseCase koji zatim poziva
metodu getScoreForGroup() repozitorija ScoreRepository, a ScoreRepository
poziva istu metodu klijenta ScoreClient. ScoreClient poziva API koji preko Firebasea
dohvaća tražene podatke i vraća ih klijentu u obliku API modela. Klijent API modele
36
pomoću konvertera (engl. Converter) pretvara u domenske modele i vraća ih
repozitoriju, koji ih zatim vraća scenariju korištenja koji ih naposljetku dostavlja
prezenteru. Valja imati na umu, da se cijela komunikacija temelji na pretplatama
izvedenim pomoću RxJave i Observable objekata, što je opisano u prethodnom
poglavlju. Nakon što prezenter dobije podatke, on ih obrađuje i pomoću mapera
stvara modele pogleda, te poziva metodu pogleda renderView() kojom šalje model
pogledu. Pogledi su realizirani da budu što jednostavniji, odnosno njihov zadatak je
isključivo prikazivanje dobivenih podataka na ekranu, npr. popunjavanje
TextViewova.
Na slici 6.6 prikazan je pojednostavljeni dijagram toka koji pokazuje put
podataka kroz aplikaciju. Pune strelice označavaju pozive metoda, a iscrtkane
predstavljaju vraćanje podataka.
Slika 6.6 Prikaz puta podataka
37
7. Izvedba aplikacije
7.1 Načini korištenja aplikacije
Prilikom prvog pokretanja aplikacije korisnik bira između prijave i anonimnog
korištenja aplikacije. Ukoliko odabere anonimni način rada, moći će bez ograničenja
pregledavati turnire, ali neće moći napraviti vlastiti turnir, niti postati moderator na
nekom postojećem turniru. Anonimni korisnik u svakom trenutku može odabrati
opciju naknadne prijave. Prijava korisnika izvedena je preko Google Sign-In usluge.
Turniri koje prati prijavljeni korisnik spremaju se u Firebase bazu podataka i dostupni
su na svakom uređaju gdje je korisnik prijavljen, dok se turniri koje prati anonimni
korisnik spremaju u memoriju uređaja. Ukoliko anonimni korisnik prati nekoliko
turnira i odluči se prijaviti, prikazivati će mu se samo turniri povezani uz njegov
Google račun, a nakon odjave ponovo će mu se prikazivati turniri koje je pratio kao
anonimni korisnik.
7.2 Praćenje turnira
Nakon pokretanja aplikacije korisnik ima mogućnost uređivanja liste turnira
koje prati. Ukoliko želi pratiti novi turnir, korisnik mora znati pristupni kod za taj turnir
i unijeti ga u polje namijenjeno za unos pristupnog koda. Nakon što korisnik unese
pristupni kod, provjerava se postoji li turnir s navedenim pristupnim kodom i ukoliko
postoji korisniku se prikazuje pregled tog turnira. Kada korisnik želi prestati pratiti
neki turnir, iz liste turnira mora povući kućicu s nazivom željenog turnira u lijevo ili
desno i turnir će se izbrisati s liste praćenja. Kako bi se spriječilo slučajno brisanje
turnira iz liste, korisniku se prikazuje poruka s opcijom da poništi zadnju akciju.
7.3 Izrada novog turnira
Izrada turnira sastoji se od unosa imena turnira, prijenosa loga na poslužitelj
(korisnik može preskočiti ovaj korak ukoliko turnir nema logo), odabira seta ikona i
boje sučelja i unosa pristupnog koda. Korisnik ima mogućnost odabira kopiranja
strukture nekog starijeg vlastitog turnira u novonastali turnir. Pod tim se
podrazumijeva kopiranje kategorija, disciplina i natjecatelja po kategorijama. Za
izradu turnira korisnik mora imati vezu s internetom kako bi se provjerila
38
jedinstvenost pristupnog koda. Korisnik koji je napravio turnir, automatski postaje
administrator tog turnira i ne može navedeni turnir maknuti s liste praćenja.
Administrator turnira može u bilo kojem trenutku obrisati turnir, čime se trajno brišu
svi podaci o turniru. Također, administrator turnira može odabrati korisnike koje će
promovirati u moderatore turnira, čime oni dobivaju mogućnost uređivanja događaja
i rezultata na turniru.
7.4 Strukturiranje turnira
Pojedini turnir može se na više načina prikazati u aplikaciji, ovisno o željama
i mašti korisnika. Osnovna jedinica turnira je kategorija, unutar koje se dodaju
natjecatelji i discipline. Kao primjer, kategorija može biti „Nogomet“, ali isto tako
kategorija može biti i „Sportovi s loptom“. Generalno je pravilo da se kategorije
grupiraju prema natjecateljima. Nakon što smo dodali kategorije i natjecatelje,
dodajemo discipline. Iako naziv „disciplina“ nije najidealniji izbor za ovaj slučaj,
disciplina predstavlja jedan dio natjecanja. Ukoliko se u nogometu prvo igra grupna
faza, a zatim eliminacijska, discipline će biti „Grupna faza“ i „Eliminacijska faza“.
Valja primijetiti da u ovom slučaju natjecatelji u grupnoj i eliminacijskoj fazi će biti
isti, stoga te dvije discipline svrstavamo u istu kategoriju. Trenutno su podržane 3
vrste disciplina. Ligaška disciplina s individualnim rezultatima idealan je odabir za
sportove gdje se gledaju rezultati pojedinaca, kao što su utrke. Rezultati mogu biti
vremena ili bodovi, te se može odabrati koji rezultat je bolji, onaj s većim ili manjim
rezultatom. Navedene postavke se biraju prilikom dodavanja nove discipline.
Rezultati se dodaju tako da se iz liste odabere ime natjecatelja za kojeg se želi
unesti rezultat i upiše njegovo vrijeme ili bodovi, ovisno o postavkama discipline.
Ligaška disciplina s duelima tipično predstavlja grupne faze natjecanja. Prilikom
izrade discipline definira se koliko bodovi nosi pobjeda, a koliko remi. Korisnik ima
mogućnost dodavanja grupa unutar discipline, pridruživanje natjecatelja pojedinoj
grupi, izradu rasporeda događanja te dodavanje rezultata. Dodavanjem novog
događaj biraju se prvi i drugi natjecatelj, kolo u kojem se događaj odigrava te datum
i vrijeme. Kod eliminacijske discipline korisnik bira početnu i završnu rundu
natjecanja (npr. četvrtfinale i finale). Događaji su prikazani kroz ždrijeb, tako da se
jednostavno može pratiti tko će igrati s kim u višoj fazi natjecanja. Dodavanje
događaja je slično kao i kod grupne faze, samo što se događaji ne dodaju po kolima,
39
već se klikne na kućicu u ždrijebu gdje se želi dodati novi događaj. Rezultati se
unose tako da se klikne na događaj za koji se želi unijeti ili izmijeniti rezultat i u
prikazani dijalog se unesu bodovi prvog i drugog tima.
7.5 Pregled turnira
Pregled turnira sastoji se od 2 ekrana, pregled kategorija i disciplina te
pregled nadolazećih događaja. Nadolazeći događaji su grupirani prema datumima
kada se odigravaju. Klikom na pojedinu disciplinu otvara se pregled odabrane
discipline čiji izgled ovisi o vrsti discipline. Ukoliko se radi o ligaškoj disciplini s
individualnim rezultatima prikazuju se rezultati natjecatelja i njihov poredak. Kod
ligaške discipline s duelima na jednom ekranu prikazuju se grupe i poredak
natjecatelja po bodovima, a na drugom ekranu je raspored svih događaja u toj
disciplini, grupiran po kolima. Pregled eliminacijske discipline prikazan je kroz
tablicu ždrijeba.
40
8. Zaključak
Aplikacija za praćenje rezultata i događaja sportskih turnira je uspješno
napravljena i spremna je za probno korištenje. Nažalost, aplikacija još nije testirana
na stvarnom turniru, no u planu je napraviti takav test prije javnog objavljivanja.
Trenutno aplikacija podržava osnovne mogućnosti za izradu i praćenje sportskih
turnira, ali planovi za daljnja poboljšanja i nove mogućnosti već postoje i spremni su
za implementaciju. Neki od tih planova su dodavanje automatskog generiranja
različitih formata rasporeda događanja, mogućnost dodavanja članova tima i
bilježenje njihovih statistika (npr. broj golova), uživo praćenje rezultata, mogućnost
praćenja turnira skeniranjem QR koda, itd.
Aplikacija je pisana prema visokim standardima, koristeći naprednu
arhitekturu i tehnologije kako bi se zadovoljila osnovna načela oblikovanja koja su:
načelo nadogradnje bez promjene, načelo inverzije ovisnosti, načelo jedinstvene
odgovornosti, načelo izdvajanja sučelja i Liskovino načelo supstitucije. Upravo to
bih izdvojio kao ključnu vrijednost ovog rada, stekavši neprocjenjiva znanja, ne
samo o razvoju Android aplikacija, već općenito o razvoju softvera.
41
9. Literatura
[1] Introduction to Activities,
https://developer.android.com/guide/components/activities/intro-
activities.html,
datum pristupa dokumentu: 2.6.2017.
[2] Android Architecture: Part 2 – the clean architecture,
http://five.agency/android-architecture-part-2-clean-architecture,
datum pristupa dokumentu: 2.6.2017.
[3] Android Development Guidelines,
Five Minutes Ltd
[4] Android Architecture: Part 3 – Applying clean architecture on Android,
http://five.agency/android-architecture-part-3-applying-clean-architecture-
android,
datum pristupa dokumentu: 2.6.2017.
[5] A detailed guide on developing Android apps using the Clean Architecture
pattern,
https://medium.com/@dmilicic/a-detailed-guide-on-developing-android-
apps-using-the-clean-architecture-pattern-d38d71e94029,
datum pristupa dokumentu: 2.6.2017.
[6] Grokking RxJava,
http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/,
datum pristupa dokumentu: 2.6.2017.
[7] Firebase Documentation,
https://firebase.google.com/docs/,
datum pristupa dokumentu: 1.6.2017.
42
10. Sažetak
Naslov:
Android aplikacija za upravljanje rasporedom i rezultatima sportskih natjecanja
Sažetak:
Organizacija sportskih turnira nije jednostavan zadatak. Aplikacija je napravljena s
namjerom da pojednostavni taj zadatak za organizatore, pružajući im centralno
mjesto na kojem mogu uređivati i pratiti raspored događanja i rezultate natjecanja,
neovisno o mjestu na kojem se nalaze. Osim organizatora, aplikacija je namijenjena
i samim natjecateljima te gledateljima omogućavajući im da u svakom trenutku
mogu provjeriti trenutno stanje rezultata i događaja turnira.
Ključne riječi:
Sport, Turnir, Natjecanje, Android, Događaji, Rezultati
Title:
Android application for managing events and results for sports competitions
Abstract:
Sports tournament organization is not an easy task. This application was made with
intention to make that task easier for organizers, giving them a central place where
they can edit and follow events and results from competition, regardless of their
location. Besides organizers, this application was also made for competitors and
viewers allowing them to check current results and events from tournament at any
time.
Keywords:
Sport, Tournament, Competition, Android, Events, Results