Högskolan i Gävle

Högskolan i Gävle
Introduktion till att skapa appar för Android
VT 2016
Eat App!
Jacob Gavin
[email protected]
Inledning
Syftet med Eat App är att få människor som inte tidigare mött varandra att få utbyta
middagar. För en ensam person kan det betyda otroligt mycket om man kan bjuda över
någon på middag. För människor som inte gillar att laga mat eller är på resande fot, så är
det ett perfekt sätt att få äta billig hemmalagad och förhoppningsvis god mat. Samtidigt
som alla får träffa nya vänner, kanske är det bara grannen som kommer över på ens
middagsevent eller en ny medborgare i landet.
Varje användare har en egen profil i Eat App. Man kan se event som är i närheten eller så
kan man söka på stad man vill se event. Ett event i Eat App är ett event där en enskild
person eller en grupp öppet bjuder in främlingar på middag. Den som lägger upp eventet
kan sätta upp filter för vilken ålder (mellan 20-30 år, mellan 50-60 år) vilket eller vilka
kön, en beskrivning av middagen (vad som serveras osv) samt vad priset för middagen är.
Om en användare ser ett event som hen vill gå på så kan man skicka en ”Request” om att
få komma på middagen och värden/värdinnan kan sen acceptera eller neka. Om värden
accepterar så skickas adressen för eventet.
Problemanalys
För att det skall kunna finnas olika användare och att man ska kunna skapa events som
andra användare ska kunna se så tänkte jag göra ett API med hjälp av Django rest
framework (Django Rest Framework, 2016). För att lagra all data använder jag ett
webbhotell som heter djangoeurope.com. De erbjuder bra datalagringsmöjligheter med
snabba servrar som ligger i Tyskland. Jag har tidigare använt deras tjänster och det har
fungerat utmärkt.
Det mesta av gränssnittet tror jag är relativt enkelt. Det kommer att behövas
specialanpassade kolumner i ListView för att kunna representera all den data jag vill ska
synas för vardera event. Layouten kommer att vara ”inbakad” i en Navigation Drawer
Activity som kommer att visa användarinfo, notifikationer och inställningar.
UI
Jag skissade fram en layout som jag
tänkt för två av skärmarna. För att
skapa ett event så tänker jag mig ett
ganska standardformulär där man
väljer/skriver i data för alla de fält som
visas på de skisserna jag har med, t ex
kött/fisk/veg, ålder på deltagarna, antal
personer och pris.
Jag följde skissen till stor del men ett
par små förändringar har skett längs
vägen. De två stora delarna av appen
är just de här två skärmarna och de var
dem två som krävde mest arbete.
Nedanför kan man se hur appen ser ut
i färdigt stadie där jag har tagit med
alla olika skärmar som appen
innehåller.
Den första skärmen till vänster är inloggningsskärmen. Här fyller användaren i sin email
och sitt lösenord, om användare väljer att kryssa i checkboxen Remember me så sparas
email och lösenord tills nästa gång användare startar appen. I mitten ser man
registreringsskärmen. Jag har valt att inte ha med att man kan välja en egen profilbild då
jag hade problem med att skicka bilder till APIn. Kan ha berott på APIn eller på java-
koden. Längst till höger är den skärm man ser efter man loggat in och en Progressbar
laddar medan RetrieveEventSync körs i bakgrunden för att hämta eventdata från APIn.
Till vänster är skärmen (fragmentet) som visar alla event i närheten (inom 50km radie) med diverse
information om eventet. I mitten är den skärmen som visar detaljerna för eventet. Om man klickar på en av
deltagarna kommer deras profilsida upp som är skärmen längst till höger. Längst upp i vänstra hörnet på
alla skärmar har man knappen för att ”dra ut” NavigationDrawern där man kan navigera till skärmen för att
lista alla event, sin profilbild, skapa event eller logga ut. På eventlist skärmen finns även ”plusknappen”
som även den skickar en till skärmen för att skapa ett event.
Implementation
Det centrala kring appen är den ListViewn som visar alla närliggande event. ListViewn
(ListEvents.java) är ett fragment som körs i MainActivity. Raderna i ListViewn är
specialanpassade för att visa den informationen som jag vill ska finnas med för vardera
event. Jag valde under arbetsprocessen att byta ut vilken typ av mat som serveras till att
istället endast visa priset som användaren som arrangerar eventet har sagt.
Under implementationen av appen så var jag osäker på vilka designpatterns jag behövde
använda mig utav för att bygga de olika delarna som behövdes. Efter att ha friskat upp
minnet om diverse olika designpatterns så kom jag fram till att för den inloggade
användaren använda mig utav en Singleton. Det vill säga en klass som, om den redan är
instansierad, returnerar sig själv vilket gör att man alltid vet att det är den aktiva
användaren som refereras till. I början hade jag delat upp det i två klasser, SessionUser
och User, där SessionUser var singletonen för den inloggade användaren och User som
lagrar information om andra användare i systemet. Efter ett tag insåg jag att det var dumt
att ha två olika klasser med i princip samma metoder och attribut så jag skapade en
abstrakt UserBase-klass där alla de delade metoderna och attributen för generella
användare fanns. Efter det blev det genast mycket enklare att arbeta med de två klasserna.
SessionUser har ett viktigt attribut som inte User har vilket är access_token.
Access_token behövs för att verifiera användaren mot APIn vid POST och GET request
när data ska hämtas/skickas.
SessionUser och User klassen skapas via en klass som jag kallar för UserManagement.
UserManagement är också en singleton som håller reda på vilka användare som har
hämtats från APIn så att när nya GET request skall göras, t ex för att hämta vilka
deltagare, så kollar systemet först med UserManagement om en viss User redan har blivit
lagrad i systemet. Om användaren redan finns lagrad så skickas ingen GET request för att
spara på bandbredd. UserManagement har alltså en ArrayList<User> som attribut och
metoder för att lägga till och ta bort användare. UserManagement har även metod för att
parsa Json objekt och skicka till APIn.
Event-klasserna är uppbyggda på ungefär samma sätt. Det finns en Event klass som har
alla attribut och metoder för Event som till exempel att konvertera datumsträngar till rätt
format samt alla getters & setters för attributen (som alla klasser har). Eventen skapas och
tas bort via EventManager som fungerar på samma sätt som UserManager.
För att inte ”låsa” huvudtråden och UI-tråden har jag skapat ett par olika AsyncTask
klasser. Dessa klasser körs i bakgrunden när de anropas och det är dem klasserna som har
hand om all kommunikation mellan APIn och appen. I början var det bara rätt mycket
jobb att få alla POST och GET request att lyckas. Det var första gången jag byggde den
typ av funktionalitet i java och android och från min forskning kring hur man gör det på
bästa sätt hittade jag så otroligt många olika lösningar och en stor del av det var till vilket
Android API man byggde för. Vissa nyare APIn hade inte samma funktionalitet för detta
som de gamla APIerna så det var en hel del testning och ändra lite, testa igen osv.
För alla AsyncTask klasser så skapade jag en Interface vars uppgift är att ”lyssna” på
AsyncTasksen och anropa en viss metod när AsyncTasken är färdig. Det tog ett tag innan
jag insåg den otroliga fördelen med att ha en Interface som håller koll på AsyncTask
processerna då jag hade en del problem med NullPointers när APIn inte skickade datan
tillräckligt snabbt till appen. När jag implementerade Interfacen försvann allt detta
eftersom att man i Interface metoden ”proccessIsFinished” kan tilldela (setText)
TextViews och liknande med den datan som hämtats från AsyncTask efter att datan
faktiskt har hämtats så att man inte försöker sätta attribut till TextViews som är null.
I inledningen skrev jag att jag ville ha med notifikationer i appen och tanken med det var
att skicka notifikationer till användare om någon ville delta i ens event man skapat eller
om man är inom en viss radie från där ett event skapas så skulle det skickas notifikation
som till exempel ”Nya event i närheten, kolla in dom!”. Detta var dock mycket svårare än
vad jag förväntade mig, hade jag haft en veckas arbetstid till så hade jag kanske fått det
att funka men jag valde att prioritera annan funktionalitet i appen som t ex att man kan se
användares profiler och registrera sig som ny användare. Jag försökte i ungeför 2 dagar
med att få notifikationer att fungera. Jag läste på en hel del om Google Cloud Messaging
(GCM) och hur hela det systemet fungerar men det var för många olika faktorer som
kunde gå fel. T ex att APIn krånglar eller att jag inte hade rätt konfigurerad GCM, diverse
olika Broadcasting och Reciever klasser som måste implementeras i appen som nog var
några steg för avancerat för tillfället men mitt nästa mål inom Android utveckling blir att
försöka komma underfund med hur det systemet fungerar.
Slutsats
Jag är väldigt nöjd över mitt arbete även om det blev lite försenat med inlämningen. Jag
är rätt säker på att jag lagt ner mer tid än vad som rekommenderades. Svårighetsgraden
som jag hade valt passade mig väldigt bra. Om det är för enkelt så tappar jag intresset för
att utföra arbetet och utvecklingen för den här appen var ibland väldigt komplex. Från
början hade jag inte alla de kunskaper som krävdes för att slutföra projektet. Jag var
tvungen att läsa på om design patterns, dock har jag läst om det tidigare en hel del men
jag behövde friska upp minnet en hel del.
Min största lärdom från det här projektet är att i början sitta ner och göra klart för sig hur
man vill att själva backend systemet ska vara. Att först skapa de klasserna eller objekten
som krävs och att verkligen tänka igenom vilken funktionalitet som ska vara kopplad till
vilka klasser. I början hade jag en metod (getAge) som från en sträng med ett
födelsedatum returnerade åldern från dagens datum. Den metoden, och andra liknande,
kopierade jag runt på lite olika ställen där jag behövde den men där jag senare insåg att
jag bara kunde ha den metoden på den abstrakta klassen UserBase, eller vilken klass den
nu bäst passade in på, vilket snyggar upp koden otroligt mycket. Det gör det även väldigt
mycket enklare att bygga vidare på appen i efterhand om man har bra strukturerad kod
och inte massa slumpmässiga metoder lite överallt.
Trots att jag gjort en hel del olika programmeringsprojekt tidigare så underskattar man
ofta hur lång tid saker och ting faktiskt tar att utföra. Man vet aldrig när man bara totalt
fastnar med en bugg och det kan ta flera timmar innan man hittar en lösning på problemet
vilket gör att det är väldigt svårt att planera. Framförallt om det är första gången man ska
testa att implementera en viss typ av funktionalitet. I framtida projekt så kommer jag att
forska och titta på många fler liknande exempel på det jag vill implementera och själv
konstatera hur mycket av det jag hittat som jag förstår och försöka räkna ut hur lång tid
jag behöver på mig. Har jag inte gjort en viss implementation tidigare så kommer jag att
räkna med att det kommer ta ganska mycket längre tid än vad jag tror från början.
Notis: jag har ännu inte lagt upp själva APIn jag byggde på ett webbhotell utan har den
enbart på en Virtual Machine (Ubuntu) på min laptop och har inte tillgång att lägga upp
APIn där. Jag ska försöka ha igång APIn så mycket som möjligt men APIn måste vara
online för att appen ska fungera eftersom all data hämtas och skickas till APIn. Om den
inte är online när du testar appen så skicka gärna ett mail till [email protected] så
kan jag förhoppningsvis sätta den online på en gång, alternativt bestämma någon tid där
jag har den online under några timmar så att ni kan testa applikationen på riktigt.