}w !"#$%&'()+,-./012345
M ASARYKOVA UNIVERZITA FAKULTA INFORMATIKY
Aplikace pro vyhledání a nákup letenek ˇ B AKALÁ RSKÁ PRÁCE
Radek Zábranský
Brno, jaro 2013
Prohlášení Prohlašuji, že tato bakaláˇrská práce je mým puvodním ˚ autorským dílem, které jsem vypracoval samostatnˇe. Všechny zdroje, prameny a literaturu, které jsem pˇri vypracování používal nebo z nich cˇ erpal, v práci rˇ ádnˇe cituji s uvedením úplného odkazu na pˇríslušný zdroj.
Radek Zábranský
Vedoucí práce: doc. RNDr. Vlastislav Dohnal, Ph.D. ii
Podˇekování V první rˇ adˇe bych rád podˇekoval doc. RNDr. Vlastislavu Dohnalovi, Ph.D. za vedení práce. Dále pak Oliveru Dlouhému za pˇríležitost tvorby této aplikace pro jeho spoleˇcnost Skypicker a Jozefu Képesimu za podporu pˇri implementaci komunikace mé aplikace se serverem Skypickeru. V neposlední rˇ adˇe bych rád podˇekoval i Bc. Ivetˇe Rebrové za testování aplikace na starší verzi systému Android, Bc. Filipu Hyžovi za pomoc se sázením textu v LATEX a Sofii Karpowiczové za finální korekturu.
iii
Klíˇcová slova mobilní aplikace, Android, Skypicker, letenky, Java, Google Maps
iv
Shrnutí Cílem práce bylo vytvoˇrení mobilní aplikace na platformu Android pro spoleˇcnost Skypicker. Aplikace je zjednodušením existující webové aplikace a slouží k vyhledání a nákupu letenek zejména nízkonákladových aerolinek. Po spuštˇení aplikace se zobrazí mapa, na které uživatel oznaˇcí oblast, kam chce letˇet. Dále muže ˚ uživatel nastavit ruzné ˚ parametry vyhledávání, zejména místo a interval odletu. Po vyhledání letu˚ se zobrazí jejich seznam, ze kterého si uživatel muže ˚ nˇekterý let vybrat, a po pˇrechodu na stránku zobrazenou ve webovém prohlížeˇci jej zakoupit. Textová cˇ ást popisuje nástroje použité pro vývoj aplikací na Android a strukturu Android aplikací. Druhá polovina práce se vˇenuje zpusobu ˚ použití Google Maps v Android aplikacích, architektuˇre aplikace Skypicker, nˇekterým detailum ˚ implementace a principu komunikace se serverovou cˇ ástí systému.
v
Obsah Úvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Vývoj aplikací pro Android . . . . . . . . . . . . . . . . . . . 1.1 Vývojové prostˇredí a ADT . . . . . . . . . . . . . . . . . 1.2 Android SDK . . . . . . . . . . . . . . . . . . . . . . . . 1.2.1 Emulátor . . . . . . . . . . . . . . . . . . . . . . . 1.2.2 DDMS . . . . . . . . . . . . . . . . . . . . . . . . 1.2.3 LogCat . . . . . . . . . . . . . . . . . . . . . . . . 2 Struktura Android aplikace . . . . . . . . . . . . . . . . . . . 2.1 AndroidManifest.xml . . . . . . . . . . . . . . . . . . . . 2.2 Zdrojové kódy jazyka Java (soubory .java) . . . . . . . . 2.2.1 Activity . . . . . . . . . . . . . . . . . . . . . . . 2.2.2 Service, Content Provider a Broadcast Receiver . 2.2.3 Fragment . . . . . . . . . . . . . . . . . . . . . . 2.3 Uživatelské rozhraní . . . . . . . . . . . . . . . . . . . . 2.4 Složky drawable a values . . . . . . . . . . . . . . . . . 3 Použití Google Maps v aplikacích . . . . . . . . . . . . . . . 3.1 API klíˇc . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Google Play Services . . . . . . . . . . . . . . . . . . . . 3.3 Úpravy AndroidManifest.xml . . . . . . . . . . . . . . . 3.4 MapFragment . . . . . . . . . . . . . . . . . . . . . . . . 4 Aplikace Skypicker . . . . . . . . . . . . . . . . . . . . . . . 4.1 Funkˇcní požadavky a uživatelské rozhraní . . . . . . . 4.2 Architektura aplikace . . . . . . . . . . . . . . . . . . . . 4.2.1 Helper . . . . . . . . . . . . . . . . . . . . . . . . 4.2.2 LoaderActivity . . . . . . . . . . . . . . . . . . . 4.2.3 MainActivity . . . . . . . . . . . . . . . . . . . . 4.2.4 Flight . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.5 FlightsFragment a FlightsAdapter . . . . . . . . 4.3 Detaily implementace . . . . . . . . . . . . . . . . . . . 4.3.1 Kruh na mapˇe a zmˇena jeho velikosti . . . . . . 4.3.2 Kód pro API 11 a vyšší . . . . . . . . . . . . . . . 4.3.3 Zmˇena intervalu vyhledávání . . . . . . . . . . . 4.3.4 Zmˇena délky pobytu . . . . . . . . . . . . . . . . 4.4 Komunikace aplikace se serverem . . . . . . . . . . . . Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 4 4 4 5 5 5 6 6 7 7 8 9 11 11 12 12 12 13 14 15 15 16 18 19 21 26 26 27 27 29 30 32 33 37 1
Úvod Webová stránka 1 brnˇenské firmy Skypicker vznikla teprve v roce 2012 [2], ale už nyní ji navštˇevuje nˇekolik tisíc uživatelu˚ dennˇe, a ˇ to nejen z Ceské republiky, ale z celé Evropy a dokonce i ze zámoˇrí. Služba, kterou na webu nalézáme, slouží k rychlému a pohodlnému vyhledávání leteckých spojení odkudkoliv kamkoliv. Mezi hlavní pˇrednosti Skypickeru a výhody oproti konkurenci patˇrí zejména rozsáhlá databáze letu. ˚ Web je však i pˇres její velikost schopen rychle nalézat lety vyhovující rozmanitým kritériím vyhledávání. Další výhodou je také nízká cena nalezených spojení, která pramení zejména z toho, že se Skypicker nebojí nabídnout svým uživatelum ˚ napˇr. let z Prahy do Finska pˇres italský Milán, protože celková cena je o nˇekolik desítek euro nižší než u pˇrímého letu. Velmi zajímavá je možnost vyhledat nejlevnˇejší lety kamkoliv, což ocení zejména lidé, kteˇrí chtˇejí levnˇe navštívit nˇejakou cizí zemi, ale nezáleží jim na tom kterou. V neposlední rˇadˇe uživatelé ocenují ˇ pˇríjemné, pˇrehledné a jednoduše použitelné uživatelské rozhraní s mapou, které je navrženo tak, aby uživatel nemusel pˇri vyhledávání vubec ˚ použít klávesnici. Všechna kritéria vyhledávání, vˇcetnˇe zemˇe odletu a cílové destinace, lze nastavit jednoduše pouze s použitím myši. Web je nicménˇe navržen pro použití na PC a ve vˇetšinˇe mobilních webových prohlížeˇcu˚ se nezobrazuje správnˇe, což jej na mobilních zaˇrízeních cˇ iní nepoužitelným. Aby mohli uživatelé Skypickeru vyhledat a zakoupit nˇejaký let i s použitím svého mobilního telefonu, bylo tedy nutné navrhnout a vyvinout mobilní verzi aplikace Skypicker. Bylo rozhodnuto o vývoji mobilních aplikací pro dva na trhu nejzastoupenˇejší mobilní operaˇcní systémy - Android a iOS. 2 Bude také vyvinuta mobilní verze webu pro použití na ostatních mobilních zaˇrízení. Vývoj aplikace Skypicker pro operaˇcní systém Android a popis jejího návrhu a implementace je právˇe hlavním pˇredmˇetem této bakaláˇrské práce. V prvních dvou kapitolách popisuji princip vývoje Android aplikací a nástroje pˇri vývoji používané. Ve tˇretí kapitole 1. http://www.skypicker.com/ 2. Operaˇcní systém firmy Apple používaný zejména na zaˇrízeních iPhone a iPad.
2
popisuji zpusob ˚ použití Google Maps 3 v Androidu, které jsou, stejnˇe jako na webu Skypickeru, použité i v jeho mobilních aplikacích. V páté nejrozsáhlejší kapitole popisuji grafické zobrazení a zpusob ˚ použití Skypicker Android aplikace uživatelem, její strukturu a nˇekteré ˇ detaily implementace. Cást kapitoly je také vˇenována zpusobu, ˚ jakým aplikace komunikuje se serverem Skypickeru.
3. Internetová mapová technologie firmy Google zobrazitelná na webu a použitelná jako souˇcást aplikací ruzných ˚ platforem.
3
1 Vývoj aplikací pro Android Vývoj aplikací pro operaˇcní systém Android probíhá zejména v programovacím jazyce Java. Kromˇe Javy je nutné, aby vývojáˇr alesponˇ na základní úrovni rozumˇel jazyku XML. Každý, kdo splnuje ˇ tyto dva požadavky, muže ˚ zaˇcít vyvíjet aplikace pro Android. V této kapitole se zabývám nástroji, které jsou k vývoji potˇrebné a nebo jej usnadnují. ˇ
1.1 Vývojové prostˇredí a ADT Snad každý, kdo nˇekdy programoval aplikace v Javˇe, používal k práci nˇejaké vývojové prostˇredí (IDE 1 ), napˇr. BlueJ, NetBeans, IntelliJ IDEA nebo Eclipse. Pˇrestože všechna tato vývojová prostˇredí lze použít pro vývoj aplikací pro Android, ne všechna jsou pro to vhodná. Je to zejména z duvodu, ˚ že nˇekterá poskytují možnosti pro usnadnˇení vývoje. Pro vývoj aplikace Skypicker jsem zvolil vývojové prostˇredí Eclipse. Google toto IDE pˇrímo podporuje, doporuˇcuje a nabízí pro nˇej zásuvný modul ADT 2 (ADT Plugin), který v nˇem usnadnuje ˇ tvorbu Android aplikací. [4] ADT umožnuje ˇ snadno vytvoˇrit nový Android projekt, vytvoˇrit uživatelské rozhraní aplikace apod. ADT dále do Eclipse integruje i nástroje Android SDK, o kterých píši dále.
1.2 Android SDK Android SDK 3 je ucelená sada vývojových nástroju˚ urˇcených pro tvorbu a testování Android aplikací. Sada obsahuje zejména Android knihovny vˇcetnˇe dokumentace, emulátor Android zaˇrízení a debugger DDMS a je dostupná pro všechny hlavní desktopové operaˇcní systémy 4 . 1. 2. 3. 4.
Integrated Development Environment. Android Development Tools. Software Development Kit. Windows, Linux i Mac OS X. [6]
4
1. V ÝVOJ APLIKACÍ PRO A NDROID 1.2.1 Emulátor Pokud vývojáˇr nemá k dispozici zaˇrízení, na kterém bˇeží Android, nebo chce svoji aplikaci testovat na zaˇrízeních s jinými parametry, než jaké má jeho fyzické zaˇrízení, je možné ke spuštˇení a testování aplikací využít právˇe emulátor. Tento velmi silný nástroj, který vývojáˇri znaˇcným zpusobem ˚ usnadnuje ˇ testování jeho aplikace, je program, který na poˇcítaˇci vývojáˇre spustí virtuální zaˇrízení s Androidem. Je s ním poté možno pracovat jako se skuteˇcným fyzickým zaˇrízením a pomocí myši simulovat dotyky obrazovky a interagovat tak se zaˇrízením a vyvíjenou aplikací. Emulátor je možno spustit s ruznými ˚ parametry, jako je napˇríklad verze operaˇcního systému Android, která na nˇem bude spuštˇena, velikost displeje, velikost RAM pamˇeti apod. 1.2.2 DDMS DDMS 5 je nástroj, který slouží ke komunikaci s již bˇežícím emulátorem nebo s pˇripojeným fyzickým zaˇrízením. Slouží k získávání aktuálních informací o stavu zaˇrízení, jako je seznam spuštˇených procesu, ˚ využití procesoru, pamˇeti, sít’ových pˇripojení apod. V pˇrípadˇe emulátoru je možné simulovat události, které nepˇricházejí skrz dotykovou vrstvu displeje. Mezi tyto události lze zaˇradit napˇríklad pˇríchozí hovor, pˇrijatou SMS zprávu nebo pˇrijatou informaci o GPS lokaci. Lze také simulovat pohyb zaˇrízení i jeho do otoˇcení horizontální polohy. 1.2.3 LogCat LogCat je nástroj integrovaný v DDMS, který umožnuje ˇ snadno nahlédnout do logu zaˇrízení, kam aplikace mohou zapisovat ruzné ˚ informace o svém stavu. Systém zde také zapisuje informace o pˇrípadné neoˇcekávané chybˇe v bˇehu aplikace, která zpusobí ˚ její pád. Pˇrístup k tˇemto informacím je klíˇcový pˇri vývoji a testování aplikací.
5. Dalvik Debug Monitor Server.
5
2 Struktura Android aplikace Aby mohla být Android aplikace zkompilována, musí její projekt obsahovat jisté soubory a dodržovat jistou strukturu. V této kapitole popisuji nejduležitˇ ˚ ejší a nejzásadnˇejší soubory této struktury. Také charakterizuji prvky, ze kterých se aplikace mohou skládat.
2.1 AndroidManifest.xml AndroidManifest.xml umístˇený v koˇrenovém adresáˇri projektu je soubor nezbytný pro každou aplikaci. Systém jej cˇ te, aby zjistil základní informace o aplikaci, které musí znát pˇredtím, než je schopen aplikaci spustit. Mimo jiné manifest obsahuje následující: •
Uvádí jméno balíku (package) aplikace jazyka Java. Tento balík slouží jako jednoznaˇcný identifikátor aplikace pro systém.
•
Uvádí verzi aplikace.
•
Deklaruje oprávnˇení, která aplikace potˇrebuje pro svuj ˚ správný bˇeh. Žádosti o tato oprávnˇení jsou uživateli zaˇrízení prezentovány pˇri instalaci aplikace a je vyžadováno jejich odsouhlasení. Mezi tato oprávnˇení patˇrí napˇríklad využívání internetového pˇripojení nebo používání nˇekterých hardwarových zaˇrízení, kterými pˇrístroj disponuje.
•
Uvádí minimální úrovenˇ API 1 , kterou musí zaˇrízení podporovat, aby na nˇem bylo možné aplikaci spustit.
•
Popisuje komponenty, ze kterých se aplikace skládá. Mezi tyto komponenty se rˇ adí objekty typu Activity, Service, Content Provider a Broadcast Receiver. Tyto komponenty popisuji v následující cˇ ásti kapitoly.
•
Uvádí vstupní bod(y) aplikace.
1. S novými verzemi Androidu se rozšiˇrují knihovny Androidu o nové tˇrídy a stávající tˇrídy o nové metody, které nemusí telefony se starší verzí Androidu podporovat.
6
2. S TRUKTURA A NDROID APLIKACE Informace o souboru AndroidManifest.xml vychází zejména z [13].
2.2 Zdrojové kódy jazyka Java (soubory .java) Soubory zdrojových kódu˚ jazyka Java jsou v Android projektu uloženy v adresáˇri src/jméno_balíku/ 2 . Mohou tu být soubory obsahující libovolné tˇrídy použité v aplikaci, ale zejména jsou zde soubory obsahující jednotlivé komponenty Android aplikace (viz 2.1). 2.2.1 Activity Aktivita (Activity) je základním stavebním kamenem každé Android aplikace, která má nˇejaké uživatelské rozhraní. Reprezentuje jednu obrazovku aplikace, se kterou uživatelé interagují. Napˇríklad jednoduchá e-mailová aplikace muže ˚ být složena ze tˇrí aktivit - aktivity, která zobrazí pˇrijaté e-maily, aktivity, která otevˇre konkrétní e-mail a umožní jeho pˇreˇctení, a aktivity, která slouží k napsání a odeslání nového e-mailu. Pˇrestože tyto aktivity spolupracují, aby daly uživateli pocit práce s jednou aplikací, jsou ve skuteˇcnosti nezávislé. Pokud to e-mailová aplikace dovolí, mohou jiné aplikace spustit kteroukoliv z tˇechto aktivit. Napˇríklad aplikace galerie, ve které se zobrazují obrázky a fotografie uložené v zaˇrízení, muže ˚ spustit aktivitu, která slouží k napsání a odeslání nového e-mailu, aby uživatel mohl obrázek odeslat. Každá aktivita musí být ve svém vlastním .java souboru a musí rozšiˇrovat (extend) tˇrídu Activity. O aktivitˇe rˇ íkáme, že má tzv. životní cyklus, což je nˇekolik stavu, ˚ ve kterých se aktivita muže ˚ za bˇehu operaˇcního systému nacházet. O pˇrechod mezi tˇemito stavy se stará operaˇcní systém, který vždy volá patˇriˇcnou metodu aktivity, aby ji informoval, že se mˇení její stav, a umožnil jí na to nˇejakým zpusobem ˚ reagovat. Tˇrída Activity, kterou musí každá aktivita rozšiˇrovat, má definované metody pro každou takovou zmˇenu stavu. Pokud chce vývojáˇr na zmˇenu stavu reagovat, musí ve své aktivitˇe 2. Jméno_balíku oznaˇcuje systém podložek korespondující se jménem balíku uvedeném v souboru AndroidManifest.xml a v každém souboru .java pomocí pˇríkazu package.
7
2. S TRUKTURA A NDROID APLIKACE pˇrekrýt patˇriˇcnou metodu a v ní implementovat kód, který se provede, když taková zmˇena nastane. Nejzásadnˇejším stavem a metodou jemu odpovídající je stav, kdy je aktivita vytvoˇrena, aby byla zobrazena uživateli. Jedná se o stav Created (vytvoˇrena) a metodu onCreate(Bundle), v níž by mˇel vývojáˇr implementovat kód pro prvotní inicializaci aktivity. Mezi další duležité ˚ stavy se rˇ adí Resumed (spuštˇena), což oznaˇcuje stav, kdy už je aktivita inicializovaná, je na popˇredí a uživatel s ní muže ˚ interagovat. Dále stav Paused (pozastavena), do nˇehož se aktivita pˇrepne, je-li pˇrekryta jinou aktivitou, ale poˇrád alesponˇ z cˇ ásti viditelná. 3 Pokud je aktivita z tohoto stavu vrácena zpˇet na popˇredí, je zavolána metoda onResume(), po níž je aktivita opˇet pˇrepnuta do stavu Resumed. Do stavu Stopped (zastavena) se aktivita pˇrepne, pˇrekryje-li jiná aktivita aktivitu úplnˇe (s aktivitou tedy není nijak možné interagovat). Pokud aktivita na popˇredí nebo nˇejaká jiná cˇ ást operaˇcního systému zaˇrízení potˇrebuje pro svuj ˚ bˇeh místo v operaˇcní pamˇeti, jehož aktuálnˇe není dostatek, muže ˚ systém ukonˇcit proces aplikace a tím i zrušit aktivity s touto aplikací spojené. Uživatel zaˇrízení ale o tom není nijak informován a pˇri návratu do dané aplikace oˇcekává, že bude ve stejném stavu, v jakém ji opustil. Tento stav lze zachovat napˇríklad pˇrekrytím metody onSaveInstanceState(Bundle), do jejíhož parametru Bundle (balík) lze ukládat hodnoty ruzných ˚ promˇenných metodami putInt(String, int), putString(String, String) apod. Parametr metody onCreate(Bundle) je právˇe balík z pˇredchozího bˇehu dané aktivity, ze kterého lze pomocí metod typu getInt(String, int) uložené hodnoty získat. 2.2.2 Service, Content Provider a Broadcast Receiver Tyto tˇri komponenty, ze kterých se muže ˚ aplikace skládat, se v aplikaci Skypicker nepoužívají, a proto je popíši jen velmi struˇcnˇe. •
Služba (Service) je komponenta, která nemá žádné uživatelské rozhraní a bˇeží na pozadí telefonu. Taková služba muže ˚ napˇríklad pˇrehrávat hudbu, zatímco uživatel používá jinou aplikaci.
•
Poskytovatel obsahu (Content Provider) spravuje pˇrístup k ur-
3. Aktivity nemusí zabírat celý displej.
8
2. S TRUKTURA A NDROID APLIKACE cˇ itému zdroji dat. Je souˇcástí Android aplikace, která obyˇcejnˇe poskytuje uživatelské rozhraní pro práci s danými daty. Content Provider také muže ˚ být využit ostatními aplikacemi pˇrímo, které pˇristupují k poskytovaným datum ˚ pomocí klienta Content Provideru. •
Pˇrijímaˇc vysílání (Broadcast Receiver) reaguje na oznámení vysílaná pro celý systém. Puvodce ˚ takových vysílání je obyˇcejnˇe operaˇcní systém, který informuje aplikace o událostech, jako je napˇríklad nízký stav baterie. Oznámení mohou vysílat i aplikace.
2.2.3 Fragment Android byl puvodnˇ ˚ e navržen jako operaˇcní systém pro telefony a obecnˇe zaˇrízení s menšími displeji. Avšak s nástupem tablet s Androidem bylo potˇreba pozmˇenit koncept, kdy celý displej byl témˇerˇ vždy zaplnˇen jednou aktivitou. Tablety mají mnohem vˇetší displej než telefony a aby byl náležitˇe využit, musela by aktivita obsahovat velké množství prvku˚ uživatelského rozhraní. Tím pádem by byla i celá implementace velmi rozsáhlá a zdrojový kód by se mohl stávat nepˇrehledným. Navíc by muselo být vytvoˇreno více verzí té samé aplikace. Jedna verze pro tablety, kde by mohlo být vše na jedné obrazovce v jedné aktivitˇe, a druhá verze pro telefony, kde by muselo obrazovek a aktivit být více. Fragmenty byly pˇredstaveny ve verzi Android 3.0 právˇe s nástupem tabletu, ˚ ale i na starších verzích Androidu je jich možné díky knihovnˇe zpˇetné kompatibility využít. Tato knihovna umožnuje ˇ vývojáˇrum ˚ používat tˇrídy a knihovny tˇríd, pˇredstavené až v novˇejších verzích Androidu, zpˇetnˇe až do API verze 4 4 . Pokud chce vývojáˇr používat fragmenty i na starších verzích Androidu, musí tuto knihovnu naimportovat do svého projektu a poté používat tˇrídy v ní obsažené. Použití fragmentu˚ s touto knihovnou se pˇríliš neliší od jejich použití na verzích Androidu, které je nativnˇe podporují. O fragmentech lze pˇremýšlet jako o modulárních sekcích spuštˇené aktivity, které mají svuj ˚ vlastní životní cyklus, pˇrijímají své vlastní vstupy a lze je do spuštˇené aktivity libovolnˇe pˇridávat a odebírat. 4. Android 1.6.
9
2. S TRUKTURA A NDROID APLIKACE Tím je umožnˇeno použít úplnˇe stejné fragmenty v aplikaci spouštˇené na telefonu i na tabletu. Pokud bych se vrátil k pˇríkladu e-mailové aplikace z kapitoly o aktivitách a implementoval funkcionalitu zobrazení pˇrijatých e-mailu˚ jako jeden fragment a zobrazení jednoho konkrétního e-mailu jako druhý fragment, mohl bych na telefonu po kliknutí na nˇejaký e-mail v prvním fragmentu vymˇenit v zaštit’ující aktivitˇe fragment za druhý, ve kterém by se zobrazil celý vybraný e-mail. Na tabletech, které mají mnohem vˇetší displeje, by mohly být oba fragmenty zobrazeny v jedné aktivitˇe zároven. ˇ Aby mohl být fragment použit, musí být vsazen do nˇejaké aktivity a jeho životní cyklus je poté pˇrímo ovlivnˇen životním cyklem aktivity. Fragment muže ˚ být do aktivity vsazen pˇrímo vložením do XML souboru definujícím její uživatelské rozhraní (viz 2.3). Pokud ale chceme fragmenty v aktivitˇe mezi sebou mˇenit, musíme je již od zaˇcátku do aktivity vkládat pomocí Java kódu. Poté je vhodné v uživatelském rozhraní definovat jistý kontejner (napˇríklad Linear Layout), do kterého budeme za použití FragmentTransaction fragmenty vkládat. V následujícím pˇríkladu je ukázáno, jakým zpusobem ˚ je možné v aktivitˇe vložit fragment MyFragment do kontejneru LinearLay out. Aby bylo možné tento kontejner, definovaný v souboru s uživatelským rozhraním, v kódu dohledat, je nutné, aby mˇel pˇridˇelený jednoznaˇcný identifikátor id. (viz 2.3) V následujícím pˇríkladu má kontejner identifikátor container. MyFragment myFragment = new MyFragment(); FragmentTransaction ft = getFragmentManager(). beginTransaction(); ft.add(R.id.container, myFragment); ft.commit(); Nejprve je vytvoˇrena nová instance fragmentu MyFragment, poté je pomocí metody getFragmentManager() získána reference na objekt, který aktivitˇe spravuje její fragmenty, a pomocí metody begin Transaction() získán objekt, který umožní provést danou transakci. Metoda add(int, Fragment) poté pˇridá daný fragment do kontejneru a metoda commit() provede pˇríslušné zmˇeny. Výmˇenu fragmentu v kontejneru je možné provést pomocí metody replace(int, Fragment). Pokud je pˇri transakci zavolána 10
2. S TRUKTURA A NDROID APLIKACE metoda addToBackStack(String), uživatel se poté muže ˚ vrátit do stavu pˇred provedením transakce pomocí tlaˇcítka zpˇet na jeho zaˇrízení.
2.3 Uživatelské rozhraní Uživatelské rozhraní se obvykle tvoˇrí mimo Java kód v XML souborech uložených v adresáˇri res/layout/. V tˇechto souborech jsou definovány jednotlivé prvky rozhraní, typicky s pˇriˇrazeným unikátním identifikátorem id. Toto rozhraní je poté naˇcteno a zobrazeno aktivitou pomocí metody setContentView(int), kde parametrem této metody je jednoznaˇcný cˇ íselný identifikátor souboru s pˇríslušným rozhraním. Pˇrístup k jednotlivým prvkum ˚ rozhraní je možný pomocí metody findViewById(int), kde parametrem této metody je opˇet jednoznaˇcný cˇ íselný identifikátor pˇríslušného prvku. Tímto je umožnˇeno oddˇelit designovou cˇ ást aplikace od samotného zdrojového kódu. Stejnˇe tak je možné vytvoˇrit více složek s rozhraními se speciálními názvy, ve kterých budou uložena rozhraní optimalizovaná pro ruzné ˚ velikosti obrazovek, hustoty pixelu˚ na displeji nebo verze Androidu. Systém pak na základˇe názvu složky vybere pˇred spuštˇením aplikace nejvhodnˇejší rozhraní, které pak použije pro zobrazení v aktivitˇe.
2.4 Složky drawable a values Posledními duležitými ˚ složkami a soubory, které zmíním, jsou složky res/drawable/, res/values/ a soubory v nich obsažené. Tyto složky obsahují konstantní data používaná v aplikaci. Ve složce drawable bývají typicky uloženy obrázky použité v aplikaci a ve složce values zase napˇr. textové popisky použité v aplikaci. Stejnˇe jako u uživatelských rozhraní podporuje systém uložení tˇechto dat do ruzných ˚ složek se speciálními názvy a systém poté vybere nejvhodnˇejší složku pro použití. Je napˇríklad možné nechat systém automaticky zvolit vhodné textové popisky podle jazyka, který je v systému nastaven, pokud jsou ovšem pro daný jazyk k dispozici pˇreklady. 11
3 Použití Google Maps v aplikacích Operaˇcní systém Android poskytuje možnost zobrazení Google Maps v aplikacích. Zpusob ˚ jejich použití se nicménˇe v nedávné dobˇe zmˇenil. V Google Maps Android v1 se k použití map v aplikaci používal prvek MapView, který vývojáˇr do aplikace vložil a v nˇemž se mapa zobrazovala. Od 3. prosince 2012 je ale MapView zavrhované (deprecated) a od 18. bˇrezna 2013 není pro nové aplikace vubec ˚ možné získat API klíˇc map verze 1, který je nutný pro jejich správné fungování. [11] Co je API klíˇc a jak jej získat, popisuji v následující cˇ ásti, která se vˇenuje Google Maps Android v2.
3.1 API klíˇc Pro správné fungování Google Maps Android je nutné, aby si vývojáˇr nechal vygenerovat privátní API klíˇc. Ten vloží do souboru AndroidManifest.xml ve své aplikaci a tím je Googlu umožnˇeno aplikaci jednoznaˇcnˇe identifikovat a sledovat její pˇrístup ke Google Maps serverum. ˚ Klíˇc je možné vygenerovat nástrojem keytool, který je obsažen v Android SDK. Nástroj vygeneruje unikátní SHA-1 otisk, který po pˇrihlášení a vložení do Google APIs Console 1 slouží k vygenerování unikátního API klíˇce. Podrobný postup je možno nalézt v dokumentaci k Google Maps Android v2. 2
3.2 Google Play Services Google Maps Android v2 využívají k provozu knihovny obsažené v Google Play Services, což je soubor služeb, který je automaticky nainstalován a aktualizován na každém zaˇrízení s Androidem ve verzi 2.2 nebo vyšší. Pokud soubor služeb Google Play Sevices není v zaˇrízení nainstalován, nebo je deaktivován, aplikace s Google Maps Android v2 nebude na takovém zaˇrízení použitelná. 1. https://code.google.com/apis/console/ - k pˇrihlášení je nutný Google úˇcet. 2. https://developers.google.com/maps/documentation/android/start
12
3. P OUŽITÍ G OOGLE M APS V APLIKACÍCH Google Play Services jsou také volitelnou souˇcástí Android SDK a pokud jich chce vývojáˇr využívat, musí na tuto knihovnu ve svém projektu odkázat. Podrobný návod lze nalézt v dokumentaci Google Play Sevices. 3 Google Play Services nicménˇe nejsou podporovány Android emulátory, a proto není testování aplikace s Google Maps Android v2 na emulátoru možné. Je tedy nutné použít skuteˇcné zaˇrízení. [12]
3.3 Úpravy AndroidManifest.xml Pro správné použití Google Maps Android v2 v aplikaci je nutné, aby soubor AndroidManifest.xml 2.1 obsahoval následující náležitosti. •
Vygenerovaný API klíˇc 3.1 , který se do manifestu pˇridává jako potomek tagu
vložením následujícího tagu, <meta-data android:name="com.google.android.maps.v2. API_KEY" android:value="API_klíˇ c" /> kde API_klíˇc je unikátní API klíˇc obdržený z Google APIs Console.
•
Definici povolení pro pˇríjem map a jeho deklaraci, <uses-permission android:name="jméno.balíku.permission. MAPS_RECEIVE" /> kde jméno.balíku je jméno balíku uvedené v manifestu a v každém zdrojovém souboru jazyka Java.
•
Další povolení, která mapy pro svuj ˚ správný bˇeh potˇrebují, deklarované v manifestu standardním zpusobem. ˚
3. http://developer.android.com/google/play-services/setup.html
13
3. P OUŽITÍ G OOGLE M APS V APLIKACÍCH
•
–
android.permission.INTERNET
–
android.permission.ACCESS_NETWORK_STATE
–
android.permission.WRITE_EXTERNAL_STORAGE
–
com.google.android.providers.gsf. permission.READ_GSERVICES
Informaci o použití OpenGL ES v2 4 , která informuje externí služby o tomto nároku aplikace s Google Maps Android v2. Zejména to má za dusledek ˚ nezobrazování aplikace v obchodˇe Google Play uživatelum, ˚ kteˇrí mají zaˇrízení bez podpory OpenGL ES v2. [8] Tato informace se do manifestu pˇridává následujícím zpusobem: <uses-feature android:glEsVersion="0x00020000" android:required="true"/>
3.4 MapFragment Je patrné, že Google se od pˇredstavení fragmentu˚ snaží vývojáˇre tlaˇcit k jejich používání. Google Maps Android v2 se totiž do uživatelského rozhraní vkládají právˇe jako fragment, konkrétnˇe Map Fragment. Tento fragment, který rozšiˇruje základní tˇrídu fragmentu˚ Fragment, byl do Android SDK pˇridán v API 12, tedy ve verzích Androidu 3.1.x. Ale i zaˇrízení s Androidem nižší verze mohou Google Maps Android v2 použít, a to za pomoci knihovny zpˇetné kompatibility (viz (2.2.3). Poté je místo fragmentu MapFragment použit SupportMapFragment.
4. Rozhraní pro zobrazování 3D grafiky.
14
4 Aplikace Skypicker V této kapitole vˇenuji vlastní implementaci aplikace Skypicker, jejíž tvorba je hlavním pˇredmˇetem této bakaláˇrské práce. V aplikaci je použita knihovna zpˇetné kompatibility, cˇ ímž by mohlo být dosaženo zpˇetné kompatibility až k verzi Android 1.6. Jelikož je ale v aplikaci také použita externí knihovna android-numberpicker 1 , je aplikace Skypicker podporována pouze do verze Android 2.2.x. Tato knihovna, která umožnuje ˇ použití tˇrídy NumberPicker na zaˇrízeních s Androidem starším než ve verzi 3.0, kdy byla do standardního SDK pˇridána, podporuje Android až od verze 2.2.x. To ale není velký problém, protože Android ve verzích starších než 2.2.x bˇeží k 3. dubnu 2013 pouze na 1,8 % všech zaˇrízení s Androidem a toto zastoupení mˇesíc od mˇesíce klesá. [14] Pˇrestože je aplikace použitelná na tabletech, nebyl na nˇe pˇri implementaci brán ohled. Aplikace je tedy optimalizovaná pro použití na telefonech a nepodporuje otoˇcení na šíˇrku. Pokud je jazyk zaˇrízení nastaven na cˇ eštinu, je aplikace spuštˇena v cˇ eštinˇe, jinak v angliˇctinˇe.
4.1 Funkˇcní požadavky a uživatelské rozhraní Vlastní návrh aplikace je prostý. Uživateli je zobrazena mapa vycentrovaná na stát, ve kterém se aktuálnˇe nachází. Nad mapou je úzký panel, ve kterém je kromˇe loga Skypickeru pˇrehled informací o aktuálním nastavení parametru˚ vyhledávání, tlaˇcítko pro otevˇrení menu a tlaˇcítko pro vyhledání letu. ˚ Parametry vyhledávání jsou zemˇe, ze které chce uživatel letˇet, interval, bˇehem kterého chce letˇet a doba setrvání v cílové destinaci. Menu slouží zejména pro nastavení tˇechto parametru. ˚ Je v nˇem také možné zmˇenit vyhledávání na pouze jednosmˇerné lety. V takovém pˇrípadˇe se nastavená doba setrvání v cílové destinaci ignoruje. Výbˇer cílové destinace probíhá kliknutím na mapu, na které se zobrazí kruh vymezující oblast, do které se budou lety vyhledávat. Pomocí znaˇcky pˇrichycené k okraji kruhu lze mˇenit velikost této 1. https://github.com/SimonVT/android-numberpicker
15
4. A PLIKACE S KYPICKER oblasti. Po kliknutí na tlaˇcítko vyhledávání je zobrazen seznam nalezených letu˚ seˇrazených od nejlevnˇejšího po nejdražší. Uživateli je umožnˇeno kliknutím na let otevˇrít ve svém webovém prohlížeˇci stránku, která ho provede rezervací patˇriˇcných letenek. Použitím tlaˇcítka zpˇet je možné vrátit se zpˇet na mapu. Snímky obrazovek jsou k nahlédnutí v další sekci na obrázcích 4.4 a 4.5.
4.2 Architektura aplikace
V následující cˇ ásti popisuji architekturu aplikace, zejména popis jednotlivých tˇríd jazyka Java v aplikaci použitých. Obsah souboru AndroidManifest.xml zde nerozebírám, jelikož prakticky kopíruje obsah nastínˇený v kapitolách 2.1 a 3.3. Na následujících dvou stranách je zobrazen diagram tˇríd aplikace. Aby bylo možné zaˇradit tyto obrázky do textu, musel být diagram rozdˇelen na dva a také musely být skryty privátní atributy tˇríd. Na prvním diagramu jsou zobrazeny aktivity aplikace a tˇrídy s nimi spojené, na druhém je poté zobrazen fragment zobrazující lety (viz 4.2.5) a související tˇrídy. Mezi tímto fragmentem a hlavní aktivitou aplikace (4.2.3) existuje vztah, který není možné na diagramu znázornit. Fragment muže ˚ být za bˇehu aplikace do aktivity pˇridán. Aktivita muže ˚ vždy mít pouze jeden fragment. 16
4. A PLIKACE S KYPICKER
Obrázek 4.1: Diagram tˇríd (aktivity) 17
4. A PLIKACE S KYPICKER
Obrázek 4.2: Diagram tˇríd (FlightsFragment)
4.2.1 Helper Soubor Helper.java popisuje tˇrídu Helper, která obsahuje metody používané v obou aktivitách aplikace. Metody byly vyˇclenˇeny do této tˇrídy, aby bylo zabránˇeno duplicitˇe kódu. Jsou využívané pro kontrolu dostupnosti internetu, který je pro fungování aplikace stˇežejní, a také pro stažení souboru˚ ze serveru Skypickeru. Detaily komunikace se serverem popisuji dále v této kapitole. 18
4. A PLIKACE S KYPICKER 4.2.2 LoaderActivity V souboru LoaderActivity.java je obsažena první ze dvou aktivit této aplikace. Slouží k inicializaci aplikace a pˇrechod na hlavní aktivitu aplikace. Využívá uživatelského rozhraní loader.xml, které nenabízí žádný zpusob ˚ interakce uživatele s aplikací. 4.3
Obrázek 4.3: LoaderActivity
Aktivita si nejprve za pomoci metody tˇrídy Helper ovˇerˇ í, zda je zaˇrízení pˇripojené k internetu. Pokud není, je uživateli zobrazen dialog vyzývající ho k pˇripojení. Nabízí mu možnost ovˇerˇ it dostupnost internetu znovu a možnost pˇrejít do nastavení telefonu pro aktivaci pˇripojení k internetu. Pokud si uživatel ani jednu z možností nevy19
4. A PLIKACE S KYPICKER bere, nebo internetové pˇripojení není stále k dispozici, aplikace bude ukonˇcena, jelikož bez internetového pˇripojení pozbývá smyslu. Pokud je vše v poˇrádku, aktivita zavolá metodu execute() na novˇe vytvoˇrené instanci privátní tˇrídy GetPositionAndStart Task, což je tˇrída rozšiˇrující tˇrídu AsyncTask, která slouží k provedení operací mimo hlavní vlákno aplikace. GetPositionAndStartTask pomocí metody tˇrídy Helper stáhne ze serveru Skypickeru všechna možná místa, ze kterých lze letˇet, dále na serveru zavolá službu, která podle IP adresy zjistí zemi, ve které se zaˇrízení aktuálnˇe nachází. Pokud nastane nˇejaká chyba, je uživateli opˇet zobrazen dialog, který ho o nastalé chybˇe informuje, vyzve ho k opakování pozdˇeji a donutí ho aplikaci zavˇrít. Tuto operaci je nutné provést mimo hlavní vlákno operace, protože pokus o komunikaci s jiným zaˇrízením v hlavním vláknˇe aplikace konˇcí na Android 3.0 a novˇejším vyvoláním výjimky NetworkOnMainThread Exception. Na starších verzích Androidu je možné takovou komunikaci provést, ale je to silnˇe nedoporuˇceno, jelikož taková akce muže ˚ zpusobit, ˚ že aplikace nebude na nˇejakou dobu reagovat. Na to muže ˚ operaˇcní systém zareagovat dokonce i zobrazením dialogového okna, které uživatele informuje o tom, že spuštˇená aplikace nereaguje, a nabídne mu její ukonˇcení. [10] Pokud jsou data stažena v poˇrádku, je nutné kromˇe názvu zemˇe, ve které se uživatel nachází, zjistit ještˇe její GPS souˇradnice, aby se na nˇe mohla mapa v následující aktivitˇe zamˇerˇ it. K tomu využívám tˇrídu Geocoder, která ovšem nefunguje 100% spolehlivˇe, a proto se nˇekdy nepodaˇrí GPS souˇradnice dané zemˇe získat. Je to známý problém, jenž má vlastní záznam na webové stránce, která slouží pro hlášení problému˚ Googlu s jeho službami. 2 Tato chyba nicménˇe nenastává cˇ asto a jelikož jediný dopad na funkˇcnost aplikace je to, že se mapa nezamˇerˇ í na zemi, ve které se uživatel nachází, je to v aplikaci ponecháno takto. Po (pokusu o) zjištˇení GPS souˇradnic zemˇe, ve které se uživatel nachází, pˇredá GetPositionAndStartTask všechna získaná data hlavní aktivitˇe aplikace a aktivitu LoaderActivity ukonˇcí.
2. http://code.google.com/p/android/issues/detail?id=38009
20
4. A PLIKACE S KYPICKER 4.2.3 MainActivity V tomto nejrozsáhlejším souboru projektu se nachází hlavní aktivita celé aplikace, MainActivity. Tato aktivita je zodpovˇedná za témˇerˇ veškerou interakci uživatele s aplikací. Zobrazuje panel s informacemi o parametrech vyhledávání, umožnuje ˇ uživateli tyto parametry zmˇenit a umožnuje ˇ provést samotné vyhledání letu. ˚ Stará se také o zobrazení mapy, o možnost oznaˇcení cílové oblasti na mapˇe a zmˇenu její velikosti. Po vyhledání letu˚ vymˇení mapu za seznam nalezených letu˚ a umožní vrátit se zpˇet k mapˇe. Aktivita má také na starosti uložení stavu aplikace v pˇrípadˇe jejího odchodu do pozadí, aby mohlo být vše obnoveno do puvodního ˚ stavu v pˇrípadˇe, že je aplikace operaˇcním systémem zastavena. Vzhled aktivity se zobrazenou mapou je na obrázku. 4.4 Inicializace MainActivity Aktivita po svém startu zobrazí uživateli dialog s nápovˇedou, která se týká zpusobu ˚ používání aplikace. Uživatel muže ˚ v dialogu zaškrtnout, že již nechce, aby se nápovˇeda pˇri startu zobrazovala. V tom pˇrípadˇe je informován, že nápovˇedu muže ˚ kdykoliv znovu otevˇrít v menu. Do nastavení aplikace, která jsou v systému pevnˇe uložená a nemˇenná ani pˇri restartování zaˇrízení, je toto uživatelovo pˇrání uloženo. Aktivita si tedy vždy pˇred zobrazením nápovˇedy ovˇerˇuje v nastaveních, zda má nápovˇedu zobrazit nebo ne. Aktivita využívá uživatelského rozhraní main.xml, ve kterém je vytvoˇreno rozložení horního panelu a vytvoˇren kontejner pro fragmenty. Aktivita poté získá reference na všechny objekty rozhraní, se kterými je potˇreba za bˇehu pracovat. Pokud již nebyla v nˇekterém z pˇredchozích bˇehu˚ vytvoˇrena instance tˇrídy SupportMapFragment a tento pˇridán do kontejneru pro fragmenty, aktivita tuto instanci získá a pomocí tˇríd FragmentManager a FragmentTransaction fragment do kontejneru pˇridá. Probíhá to zpusobem ˚ zmínˇeným v kapitole o fragmentech. 2.2.3 Pokud existuje uložený stav z pˇredchozího bˇehu aktivity, je tento obnoven, pokud ne, je aktivita inicializována na výchozí hodnoty. Je také inicializováno menu, ve kterém je možné zmˇenit poˇcáteˇcní zemi vyhledávání, interval odletu, dobu setrvání v cílové destinaci, 21
4. A PLIKACE S KYPICKER
Obrázek 4.4: MainActivity s MapFragmentem
pˇrípadnˇe zda si uživatel pˇreje vyhledávat pouze jednosmˇerné lety. Dále je v menu možné vyhledat lety kamkoliv. V tom pˇrípadˇe není potˇreba, aby byla na mapˇe oznaˇcena nˇejaká oblast, pˇrípadnˇe se tato ignoruje, a uživateli jsou zobrazeny nejlevnˇejší lety ze zvolené zemˇe úplnˇe Dále jsou nastaveny posluchaˇce (listener) ke všem prvkum, ˚ se kterými uživatel interaguje. Jedná se o tˇrídy, jejichž metody jsou zavolány, napˇríklad pokud uživatel klikne na tlaˇcítko vyhledávání, nebo pokud je napˇríklad zmˇenˇen stav zaškrtávacího boxu v nápovˇedˇe. Také je nastaven posluchaˇc, jehož kód se vykoná, pokud je zmˇenˇen zásobník fragmentu. ˚ Do zásobníku fragmentu˚ lze pˇri výmˇenˇe fragmentu˚ 22
4. A PLIKACE S KYPICKER pomocí tˇrídy FragmentTransaction tuto zmˇenu uložit, aby bylo poté možné se k ní vracet. Tento posluchaˇc slouží pouze k tomu, aby v pˇrípadˇe pˇrechodu na zobrazení seznamu letu˚ byla na horním panelu zobrazena šipka umožnující ˇ návrat zpˇet na mapu, a aby byla opˇet schována, pokud k návratu na mapu dojde a další vyvolání akce zpˇet by znamenalo ukonˇcení aplikace. Všechny pˇredchozí kroky se dˇely v metodˇe onCreate(Bundle). Jelikož ale bˇehem vykonávání kódu v této metodˇe nejsou objekty a metody mapy ještˇe inicializovány a jejich použití by zpusobovalo ˚ chyby, je nutné veškeré nastavení mapy provést až v metodˇe onResume(). Zde opˇet pˇrichází na rˇ adu stav uložený z pˇredchozího bˇehu aktivity. Pokud nˇejaký existuje, jsou jeho hodnoty použity pro inicializaci mapy. Tyto hodnoty jsou souˇradnice, na které je mapa zamˇerˇ ena, její pˇriblížení, dále zda byl na mapˇe pˇri pˇredchozím bˇehu umístˇen kruh, pˇrípadnˇe jeho umístˇení a polomˇer. Pokud žádný stav s pˇredchozího bˇehu neexistuje, je mapa inicializována na výchozí pˇriblížení a zamˇerˇ ení je nastaveno na souˇradnice získané v LoaderActivity. Pokud nebylo možné v LoaderActivity kvuli ˚ problémum ˚ s tˇrídou Geocoder (viz 4.2.2) souˇradnice získat, je uživateli v dialogu zobrazeno oznámení a zamˇerˇ ení mapy se v takovém pˇrípadˇe nezmˇení. Je nastaveno na výchozí hodnotu pˇri inicializaci mapy, což je zamˇerˇ ení na souˇradnice, kde se nultý poledník protíná s rovníkem. Posledním krokem pˇri inicializaci aktivity je zavolání metody, která ovˇerˇ í, zda nejsou datumy nastavené jako interval vyhledávání zastaralé. Je totiž možné, že pˇredchozí bˇeh aktivity se konal pˇred nˇekolika dny a po obnovení uloženého stavu z tohoto bˇehu se nastaví interval tak, jak byl nastaven pˇredtím. V takovém pˇrípadˇe by se mohlo stát, že by vyhledávací interval zasahoval do minulosti. Pˇrestože je server proti takovým vyhledávacím parametrum ˚ chránˇený a jednoduše nevrátí v intervalu v minulosti žádné lety, není žádoucí nechat uživatele vyhledávat lety v minulosti.
Bˇeh MainActivity a interakce s uživatelem Zde popisuji nˇekteré zásadní akce, které muže ˚ uživatel provádˇet, a metody, které se o obsluhu tˇechto akcí starají. 23
4. A PLIKACE S KYPICKER •
Nejzásadnˇejší akcí je zcela jistˇe vyhledání letu. ˚ O to se stará metoda performSearch(boolean). Parametr boolean má metoda z toho duvodu, ˚ že inicializace vyhledání letu˚ muže ˚ být uživatelem provedena ze dvou ruzných ˚ míst a je potˇreba mezi tˇemito možnostmi rozlišovat. V obou pˇrípadech je zavolána metoda execute(Double...) 3 privátní tˇrídy GetFlights Task, což je obdoba tˇrídy GetPositionAndStartTask z LoaderActivity (viz 4.2.2) sloužící k vyhledání letu˚ a výmˇenu fragmentu MapFragment za FlightsFragment se zobrazenými výsledky vyhledávání. Rozdíl je v tom, že v pˇrípadˇe vyhledávání letu˚ kamkoliv z menu nejsou parametry pˇredané metodˇe execute(Double...) žádné, pˇri vyhledání pomocí tlaˇcítka vyhledávání na horní lištˇe jsou metodˇe pˇredány parametry odpovídající souˇradnicím stˇredu kruhu a jeho polomˇeru. Vzhled aktivity po vyhledání letu˚ je patrný na obrázku 4.5.
•
Dalšími duležitými ˚ operacemi jsou umístˇení kruhu na mapu a zmˇena jeho velikosti. Umístˇení se dˇeje jednoduše pomocí zavolání metody tˇrídy GoogleMap, což je instance mapy, referenci na níž získávám v metodˇe onCreate(Bundle). Pokud už je nˇejaký kruh na mapˇe umístˇen a uživatel klikne na jiné místo na mapˇe, je pouze kruhu zmˇenˇena pozice stˇredu, což zpusobí ˚ jeho pˇresun. Souˇcasnˇe s umístˇením kruhu je na mapu umístˇena také instance tˇrídy Marker, která tvoˇrí znaˇcku (viz obrázek 4.4) používanou ke zmˇenˇe velikosti kruhu. Kruh má pˇri prvním pˇridání na mapu nastaven polomˇer na 250 km a uživatel jej muže ˚ zvˇetšit až na 500 km cˇ i zmenšit až na 100 km. Maximální omezení je nastaveno z duvodu ˚ složitého vyhledávání pˇri pˇríliš velkém polomˇeru kruhu, minimální omezení je nastaveno, protože pˇríliš malý kruh nevypadá na mapˇe dobˇre. I v rozmezí tohoto intervalu nemuže ˚ uživatel nastavit velikost kruhu na libovolnou velikost, ale polomˇer se mˇení pouze po 25 kilometrových skocích. Duvodem ˚ pro tuto volbu je, aby se kruh nemusel pˇri zmˇenˇe jeho velikosti pˇríliš cˇ asto pˇrekreslovat, což dˇelá po-
3. Parametr Double... znaˇcí možnost zavolání této metody s libovolným poˇctem hodnot typu Double. Tento zápis ze nazývá Varargs a jeho popis je k nahlédnutí napˇríklad na následující webové stránce http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
24
4. A PLIKACE S KYPICKER
Obrázek 4.5: MainActivity s FlightsFragmentem
malejším zaˇrízením problémy. Implementaci umístˇení znaˇcky na dolní okraj kruhu a jejího použití pro zmˇenu velikosti kruhu popisuji v kapitole 4.3.1. •
Zmˇena intervalu vyhledávání probíhá v dialogu zobrazeném po výbˇeru patˇriˇcné položky v menu. Uživatel je nejprve dotázán, zda chce mˇenit poˇcáteˇcní nebo koncové datum intervalu. Poté je zobrazena instance tˇrídy DatePickerDialog, ve které muže ˚ uživatel vybrané datum zmˇenit. Zmˇena data je omezena na interval od dvou dnu˚ po aktuálním dni 4 do pul ˚ roku po ak-
4. Den, kdy uživatel aplikaci používá.
25
4. A PLIKACE S KYPICKER tuálním dni. Toto omezení lze nastavit pomocí metod setMin Date(long), resp. setMaxDate(long), které jsou volány na instanci tˇrídy DatePicker, na níž je získána reference z instance DatePickerDialog. Toto omezení bohužel není možné nastavit na Androidu v nižší verzi než 3.0, a proto je uživatel zaˇrízení s tˇemito staršími verzemi pouze informován o omezení intervalu s tím, že pokud nastaví datum mimo interval, bude jeho volba ignorována. Zárovenˇ není možné nastavit koncové datum intervalu pˇred poˇcáteˇcní. Podrobný zpusob ˚ implementace popisuji v kapitole 4.3.3. •
Nastavení doby setrvání v cílové oblasti, která muže ˚ být maximálnˇe 14 dní, je opˇet možné pomocí výbˇeru pˇríslušné položky z menu. Uživatel je opˇet prezentován dialogem, jenž je tentokrát vytvoˇren pomocí uživatelského rozhraní definovaného v numberpicker_dialog.xml. V rozhraní je na vrchu zobrazen zaškrtávací box, kterým uživatel muže ˚ zmˇenit vyhledávané lety pouze na jednosmˇerné. Pod ním jsou vedle sebe dvˇe instance tˇrídy NumberPicker. V Androidu ve verzi 3.0 je použita standardní tˇrída NumberPicker obsažená v Android SDK, ve starších verzích je použita tˇrída z knihovny android -numberpicker, kterou zminuji ˇ na zaˇcátku kapitoly 4. Zpusob ˚ vytvoˇrení dialogu ze souboru uživatelského rozhraní a zpusob, ˚ kterým používám dvˇe ruzné ˚ tˇrídy se stejným jménem v jedné aplikaci, popisuji v kapitole 4.3.4.
4.2.4 Flight Soubor Flight.java obsahuje veˇrejnou tˇrídu Flight, která reprezentuje nalezený let. Privátní parametry této tˇrídy obsahují hodnoty, jako je výchozí místo letu, cílové místo letu, cena letu a podobnˇe. Pro pˇrístup k tˇemto parametrum ˚ má tˇrída nadefinovány pˇríslušné metody. 4.2.5 FlightsFragment a FlightsAdapter FlightsFragment.java obsahuje tˇrídu FlightsFragment zodpovˇednou za zobrazení nalezených letu. ˚ Tato tˇrída rozšiˇruje tˇrídu 26
4. A PLIKACE S KYPICKER ListFragment, což je speciální fragment obsažený v Android SDK, který umožní jednoduše zobrazit seznam položek. Vzhled každé položky je definován v rozhraní flights_row.xml, které je pˇredáno jako parametr tˇrídˇe FlightsAdapter. Ta je definovaná v souboru FlightsAdapter.java a rozšiˇruje tˇrídu ArrayAdapter, již ListFragment pro zobrazení seznamu používá. Kromˇe uživatelského rozhraní je FlightsAdapteru pˇredán také List naplnˇený instancemi tˇrídy Flight. Ty FlightsFragment vytvoˇrí zpracováním výsledku vyhledání letu, ˚ který je mu pˇredán z tˇrídy GetFlights Task. FlightsAdapter má na starosti právˇe správné zobrazení informací o letu v každé z položek zobrazených v seznamu.
4.3 Detaily implementace 4.3.1 Kruh na mapˇe a zmˇena jeho velikosti Pˇri inicializaci mapy je jí pˇriˇrazena nová instance tˇrídy OnMapClick Listener, jejíž metoda onClick(LatLng) je zavolána pokaždé, když uživatel klikne na mapu. Parametr této metody uchovává zemˇepisné souˇradnice, na kterých kliknutí probˇehlo. Parametr je pˇredán metodˇe putCircleOnMap(LatLng), která pˇridá kruh na mapu, nebo zmˇení jeho polohu, pokud už na mapˇe nˇejaký kruh zobrazený je. Souˇcasnˇe s umístˇením kruhu je ale potˇreba umístit na nejjižnˇejší bod jeho hrany i znaˇcku, která slouží pro zmˇenu jeho velikosti. Výpoˇcet souˇradnice bodu, na který znaˇcku umístit, probíhá v metodˇe get CircleBottomLatitude(double, double). Parametry této metody jsou zemˇepisná šíˇrka stˇredu kruhu a jeho polomˇer. Výpoˇcet využívá vzdálenosti mezi rovnobˇežkami pˇrevzaté z [15], která je prakticky stejná poblíž rovníku i pólu. ˚ Metoda se snaží skuteˇcné vzdálenosti pˇriblížit pomocí znalosti umístˇení stˇredu kruhu a jeho polomˇeru, jedná se ale pouze o aproximaci. Pˇri dostateˇcném pˇriblížení je patrné, že znaˇcka není umístˇena pˇresnˇe na okraji kruhu. Pro potˇreby aplikace je to ale dostaˇcující, protože pˇri bˇežném používání aplikace k takovému pˇriblížení nedojde a tento nedostatek tedy není patrný. Pˇri inicializaci mapy je jí rovnˇež pˇriˇrazen další posluchaˇc, který sleduje uživateluv ˚ zámˇer o pohyb se znaˇckou. Tento posluchaˇc obsahuje tˇri metody, jejichž kód je vykonán pˇri zaˇcátku pohybu se znaˇckou, bˇehem jejího pohybu a pˇri ukonˇcení pohybu, tedy kdy uživatel zvedne 27
4. A PLIKACE S KYPICKER prst z displeje. Pˇri zaˇcátku pohybu je v levém dolním rohu zobrazeno malé okénko s textem, které uživatele informuje o polomˇeru kruhu bˇehem zmˇeny jeho velikosti. Toto okénko je po ukonˇcení pohybu opˇet skryto. Po ukonˇcení pohybu jsou rovnˇež zavolány metody, které umístí znaˇcku zpˇet na nejjižnˇejší bod hrany kruhu. Kromˇe tohoto se obsah tˇrí metod definovaných v posluchaˇci nijak neliší. Všechny tˇri volají metodu updateCircleRadius(Marker), které je jako parametr znaˇcka pˇredána a cˇ ást jejíhož zdrojového kódu zde uvádím: private void updateCircleRadius(Marker marker) { Location markerLocation = new Location(""); markerLocation.setLatitude(marker. getPosition().latitude); markerLocation.setLongitude(marker. getPosition().longitude); long newRadius = (long) markerLocation. distanceTo(circleLocation); newRadius += CIRCLE_RADIUS_FACTOR / 2; newRadius -= newRadius % CIRCLE_RADIUS_FACTOR; if (newRadius > CIRCLE_MIN_RADIUS && newRadius < CIRCLE_MAX_RADIUS && newRadius != circle.getRadius()) { circle.setRadius(newRadius); } else if (newRadius <= CIRCLE_MIN_RADIUS && circle.getRadius() > CIRCLE_MIN_RADIUS) { circle.setRadius(CIRCLE_MIN_RADIUS); } else if (newRadius >= CIRCLE_MAX_RADIUS && circle.getRadius() < CIRCLE_MAX_RADIUS) { circle.setRadius(CIRCLE_MAX_RADIUS); } } Z ukázky byly vynechány cˇ ásti kódu zodpovˇedné za aktualizaci informaˇcního okénka informujícího uživatele o aktuálním polomˇeru kruhu. Umístˇení kruhu je vloženo do nové instance tˇrídy Loaction, která pomocí metody distanceTo(Location) umí spoˇcítat vzdá28
4. A PLIKACE S KYPICKER lenost mezi dvˇema zemˇepisnými body. Promˇenná circleLocation je promˇenná tˇrídy MainActivity, do které se ukládá poloha kruhu pˇri její zmˇenˇe. Vypoˇcítaná vzdálenost je uložena do promˇenné new Radius, k níž je pˇripoˇcítána polovina statické promˇenné CIRCLE_ RADIUS_FACTOR (dále faktor), která definuje skoky, po kterých je možné polomˇer kruhu mˇenit (viz 4.2.3). Poté je od vzdálenosti odecˇ ten zbytek po jejím dˇelení faktorem. Tˇemito dvˇema operacemi je dosaženo jednak toho, že se polomˇer kruhu mˇení po definovaných skocích, a také toho, že polomˇer bude vždy takový, aby okraj kruhu byl ke znaˇcce co nejdˇríve. Jako pˇríklad uvedu vypoˇcítanou vzdálenost mezi stˇredem kruhu a aktuální pozicí znaˇcky 212 km. Pokud je faktor nastavena na 25, jak v aplikaci skuteˇcnˇe je, zmˇení se vzdálenost pro pˇriˇctení její poloviny na 224,5 km. Zbytek po dˇelení vzdálenosti faktorem tedy vyjde 24,5 a po jeho odeˇctení od vzdálenosti získáme finální polomˇer 200 km. Pokud je však aktuální vzdálenost mezi stˇredem kruhu a znaˇckou 213 km, získáme stejným výpoˇctem už finální polomˇer 225 km. Zbytek metody kontroluje, zda vypoˇctená vzdálenost není menší nebo vˇetší než minimální, resp. maximální polomˇer, který kruh muže ˚ být. V takovém pˇrípadˇe je nastaven polomˇer na tuto minimální, resp. maximální hodnotu, v opaˇcném pˇrípadˇe je nastaven na vypoˇctenou hodnotu. Speciální pozornost si zaslouží cˇ ást podmínka if, resp. její cˇ ást newRadius != circle.getRadius(). Ta zajistí, že se polomˇer kruhu nenastavuje, pokud by byl nastaven na stejnou hodnotu, kterou už má. Tím se zabrání pˇrekreslení kruhu, které je vždy uživatelem postˇrehnutelné, protože má za dusledek ˚ krátké zmizení výplnˇe kruhu pˇredtím, než je vykreslena znovu. 4.3.2 Kód pro API 11 a vyšší Nˇekteré objekty a metody použité v aplikaci byly do Android SDK pˇridány až v API 11 (Android 3.0), jelikož však aplikace zpˇetnˇe podporuje zaˇrízení až do API 8, což je také deklarováno v souboru AndoridManifest.xml, vývojové prostˇredí odmítá zdrojový kód s tˇemito objekty a metodami pˇreložit. Práci s tˇemito objekty a metodami se tedy musí vyˇclenit do samostatných metod, pˇred které je potˇreba pˇridat speciální anotaci @TargetApi(11), která zpusobí, ˚ že kód v metodˇe bude vývojové prostˇredí kontrolovat, jako kdyby se kompilo29
4. A PLIKACE S KYPICKER valo pro API 11 a vyšší. Tyto metody je poté nutné volat uvnitˇr bloku, který ovˇerˇ í, že verze API, na níž aplikace bˇeží, je skuteˇcnˇe 11 nebo vyšší. Toto lze kontrolovat následující podmínkou: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // kód urˇ cený pro API 11 a vyšší } 4.3.3 Zmˇena intervalu vyhledávání Zmˇenu intervalu vyhledávání má na starosti metoda editDepartureInterval(boolean), jejíž parametr urˇcuje, zda se bude mˇenit poˇcáteˇcní nebo koncové datum intervalu. Metoda vytvoˇrí novou instanci tˇrídy DatePickerDialog, které je jako parametr pˇredán posluchaˇc OnDateSetListener, kód jehož metody onDateSet(DatePicker, int, int, int) se vykoná, když uživatel potvrdí svojí volbu. Dalšími parametry pˇredanými dialogu jsou výchozí hodnoty, na které se má nastavit. Tyto hodnoty jsou den, mˇesíc a rok aktuálnˇe nastavené jako pˇríslušné datum intervalu. Po inicializaci jsou poté na verzích Androidu 3.0 a vyšších následujícím zpusobem ˚ nastaveny limity výbˇeru data (viz 4.2.3): cal.add(Calendar.MONTH, 6); setCalendarToDaysThreshold(cal, false); api11_setDatePickerMinMaxDate(dpd, cal, false); cal.add(Calendar.MONTH, -6); cal.add(Calendar.DATE, 2); setCalendarToDaysThreshold(cal, true); api11_setDatePickerMinMaxDate(dpd, cal, true); Tato ukázka pochází z inicializace dialogu pro výbˇer poˇcáteˇcního data intervalu. Nastavení limitu˚ u dialogu pro výbˇer koncového data probíhá prakticky stejnˇe s tím rozdílem, že jako minimální zvolitelné datum je nastaveno aktuální poˇcáteˇcní datum intervalu. Ukázka byla rovnˇež pro potˇreby tohoto textu drobnˇe upravena, její funkˇcnost ale zustává ˚ stejná jako ve vlastním zdrojovém kódu aplikace. Promˇenná cal je instancí tˇrídy Calendar s nastaveným aktuálˇ tohoto kalendáˇre je posunut o 6 mˇesícu˚ dopˇredu a ním cˇ asem. Cas 30
4. A PLIKACE S KYPICKER datum, které nyní reprezentuje, je nastaveno jako maximální datum metodou api11_setDatePickerMinMaxDate(DatePickerDia log, Calendar, boolean). Parametr boolean této metody urcˇ uje, zda má metoda nastavit minimální nebo maximální datum. Promˇenná dpd je reference na dialog, jehož hodnoty jsou právˇe nastaˇ kalendáˇre je poté vrácen zpˇet do souˇcasnosti a posunut vovány. Cas vpˇred o dva dny. Datum, které je nyní kalendáˇrem reprezentováno, je nastaveno jako minimální datum daného dialogu. Vždy pˇred samotným nastavením dialogu je volána metoda set CalendarToDaysThreshold(Calendar, boolean), která v závislosti na parametru boolean nastaví cˇ as v kalendáˇri na úplnˇe první nebo na úplnˇe poslední milisekundu daného dne. Bez toho se totiž stávalo, že vybral-li uživatel jako nˇekteré datum intervalu napˇríklad maximální možné datum a potom se pokusil toto datum upravit znovu, aplikace byla ukonˇcena s výjimkou IllegalArgumentException. Problém byl v tom, že datum, které lze v dialogu maximálnˇe vybrat, se dialogu nastavuje pomocí milisekund ubˇehnutých od tzv. „Unixové epochy“ 5 . Navzdory tomu pˇri tvorbˇe instance DatePickerDialog se výchozí datum dialogu pˇredává pouze pomocí dne, mˇesíce a roku. Dialog ovšem toto datum pˇrevede na milisekundy ubˇehnuté od epochy a tyto porovná s milisekundami ubˇehnutými od epochy nastavenými jako maximální datum. Stávalo se tedy, že pˇrestože se jednalo o stejný den, cˇ íslo reprezentující milisekundy ubˇehnuté od epochy nastavené jako výchozí datum dialogu bylo vˇetší než cˇ íslo nastavené jako maximální datum dialogu, což vedlo ke zmínˇené výjimce. Zmˇena nastaveného data probíhá uvnitˇr metody posluchaˇce onDa teSet(DatePicker, int, int, int). V této metodˇe je potˇreba zohlednit, zda je kód vykonáván na zaˇrízení s Androidem 3.0 nebo novˇejším. Pokud ne, je potˇreba ovˇerˇ it, zda uživatelem nastavené datum je uvnitˇr dialogem prezentovaného intervalu (viz 4.2.3). V pˇrípadˇe, že není, datum není zmˇenˇeno. Pokud ano, vykoná se na všech verzích Androidu stejný kód. Pˇredpokládejme, že uživatel mˇenil nastavení poˇcáteˇcního data vyhledávacího intervalu. Poté jsou tˇri parametry typu int metody onDateSet(DatePicker, int, int, int), které reprezentují vybraný rok, mˇesíc a den, uloženy do pˇríslušných promˇenných MainActivity, ale souˇcasnˇe je tˇemito hodnotami inici5. Pulnoc ˚ 1. ledna 1970 - http://en.wikipedia.org/wiki/Unix_time
31
4. A PLIKACE S KYPICKER alizována i instance typu Calendar. Druhá instance typu Calendar je inicializována hodnotami data reprezentujícího konec intervalu. Datumy reprezentované tˇemito kalendáˇri jsou poté porovnané a je-li zjištˇeno, že uživatelem vybrané poˇcáteˇcní datum intervalu je pozdˇeji než jeho koncové datum, je na stejný den nastaveno i koncové datum. 4.3.4 Zmˇena délky pobytu Zmˇena délky pobytu probíhá pomocí nastavení hodnot na dvou instancích tˇrídy NumberPicker. Design dialogu je vytvoˇren ze souboru uživatelského rozhraní numberpicker_dialog.xml, pomocí následujícího kódu v metodˇe onCreate(Bundle): intervalPickerDialogBody = getLayoutInflater() .inflate(R.layout.numberpicker_dialog, null); Promˇenná intervalPickerDialogBody je tˇrídy View, která je poté pˇri vytváˇrení dialogu pˇredána metodˇe setView(View) tˇrídy AlertDialog.Builder. V Androidu 3.0 a novˇejším je použita standardní tˇrída Number Picker obsažená v Android SDK. Ve starších verzích systému Android, kde tato tˇrída není k dispozici, je použita tˇrída se stejným názvem, ale z externí knihovny android-numberpicker. Tato tˇrída je tedy následujícím zpusobem ˚ použita v uživatelském rozhraní: Net.simonvt.numberpicker je název balíku knihovního projektu obsahujícího tuto tˇrídu. Do Java souboru MainActivity.java je poté tato tˇrída naimportována následujícím pˇríkazem: import net.simonvt.numberpicker.NumberPicker; Reference na instanci definovanou v uživatelském rozhraní je získána následovnˇe: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 32
4. A PLIKACE S KYPICKER api11_intervalPicker1 = (android.widget .NumberPicker) intervalPickerDialogBody .findViewById(R.id.interval_picker_1); } else { intervalPicker1 = (NumberPicker) intervalPickerDialogBody .findViewById(R.id.interval_picker_1); } Tento kód využívá pravdˇepodobné chyby v tˇrídˇe LayoutInfla ter, která se nejprve pokouší najít už nˇekdy dˇríve použitou tˇrídu s názvem definovaným v uživatelském rozhraní, ignorujíc prefix tˇrídy. [20] Na zaˇrízeních s Androidem 3.0 a novˇejším tedy LayoutIn flater pro tˇrídu net.simonvt.numberpicker.NumberPicker nalezne tˇrídu android.widget.NumberPicker a tu použije. Zaˇrízení se starším androidem tˇrídu android.widget.NumberPicker neznají, a proto použijí tˇrídu z externí knihovny.
4.4 Komunikace aplikace se serverem Veškerou komunikaci aplikace se serverem Skypickeru provádí metoda loadJSON(String) tˇrídy Helper. Data stahovaná ze serveru jsou získána pomocí protokolu HTTP metodou GET. Zde uvádím nejduležitˇ ˚ ejší cˇ ást metody loadJSON(String) a struˇcnˇe popisuji její fungování. DefaultHttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(API_URL + apiResource); HttpResponse res = client.execute(get); is = res.getEntity().getContent(); isr = new InputStreamReader(is); br = new BufferedReader(isr); while ((s = br.readLine()) != null) { content += s; } 33
4. A PLIKACE S KYPICKER Tˇrída DefaultHttpClient umožnuje ˇ použití HTTP protokolu, v tomto pˇrípadˇe metody HTTP GET reprezentované tˇrídou HttpGet. Parametrem konstruktoru této tˇrídy je URL vzdálené služby, po které požadujeme data. 6 Výsledkem tohoto požadavku je odpovˇed’ serveru, což je, pokud všechno probˇehlo v poˇrádku, právˇe požadovaný JSON soubor. Tento je uložen do promˇenné String content, která je vrácena jako výsledek metody. JSON (JavaScript Object Notation) je pojmenování pro zpusob ˚ zápisu dat urˇcených pro pˇrenos, která jsou poslána formou textového rˇ etˇezce. Hlavními pˇrednostmi JSON rˇ etˇezce je to, že je jednoduše vytvoˇritelný i cˇ itelný jak pro lidi, tak pro poˇcítaˇce. [3]. Asi nejduležitˇ ˚ ejší služba serveru, po které aplikace požaduje data, je služba bˇežící na adrese http://www.skypicker.com/flights. Služba umožnuje ˇ podle zadaných parametru˚ vyhledání letu, ˚ jejichž seznam je vrácen jako výsledek její operace. Tento seznam je právˇe ve formátu JSON. Základní strukturu JSON souboru tvoˇrí objekty ohraniˇcené složenými závorkami, které obsahují libovolné množství dvojic ”název”:hodnota oddˇelených cˇ árkami. Hodnotou muže ˚ být napˇríklad rˇ etˇezec nebo cˇ íslo, ale i další objekt. Objekty mohou být dále organizovány do polí ohraniˇcených hranatými závorkami, které mohou být také hodnotami. Odpovˇed’ služby dostupné na adrese http://www.skypicker .com/flights muže ˚ vypadat napˇríklad takto: { "connections":[ { "id":"AGP", "name":"Malaga" }, { "id":"AMS", "name":"Amsterdam" }, ... 6. Statická promˇenná API_URL reprezentuje URL serveru Skypickeru, apiRe source je vstupním parametrem metody loadJSON(String) reprezentujícím volanou službu vˇcetnˇe pˇrípadných parametru. ˚
34
4. A PLIKACE S KYPICKER ], "data":[ { "price":129.7620007833, "cityFrom":"Prague", "flyFrom":"PRG", "dTime":1369046700, "id":"5032437|6248114", "route":[ { "price":57.9599990845, ... }, ... ], ... }, ... ], "time":0.05 } Jak je vidˇet, je celý JSON soubor letu˚ pouze jedním objektem obsahujícím tˇri hodnoty s názvy connections, data a time. Hodnota connections obsahuje pole všech letišt’, která figurují v nalezených letech. Hodnota time urˇcuje cˇ as, který server potˇreboval ke zpracování požadavku. Ani jedna z tˇechto hodnot se v Android aplikaci Skypicker nevyužívá. Využita je pouze hodnota s názvem data obsahující právˇe seznam nalezených letu. ˚ Každý let obsahuje základní informace o své cenˇe, mˇestˇe a letišti odletu apod. Celkem asi 20 informací, z nichž nˇekteré aplikace pro svuj ˚ bˇeh využívá, nˇekteré ne. Zvláštní hodnotou každého letu je pole route, které obsahuje seznam dílˇcích letu, ˚ ze kterých se let skládá. Tyto lety ovšem opˇet nejsou v aplikaci využity, pouze je vždy spoˇcítán jejich poˇcet pro zjištˇení poˇctu pˇrestupu. ˚ Parsování JSON souboru je vždy provádˇeno v metodách, které metodu loadJSON(String) pro jeho stažení využily.
35
Závˇer Cílem práce bylo vytvoˇrit aplikaci pro vyhledání a nákup letenek na platformu Android pro firmu Skypicker, což se bez vˇetších problému˚ podaˇrilo. Aplikace nicménˇe nákup letenek neumožnuje, ˇ jelikož po výbˇeru nˇekterého z nalezených letu˚ má být uživateli zobrazena webová stránka, na které muže ˚ nákup provést, ale Skypicker nemá k datu 14. 5. 2012 tuto stránku ještˇe v provozu. Naˇcítání webové stránky tedy skonˇcí chybou. Toto bohužel nemohu nijak ovlivnit. Bˇehem vývoje mˇe napadala ruzná ˚ vylepšení, která by bylo možné v aplikaci implementovat. Jedná se napˇríklad o možnost seˇrazování nalezených letu˚ podle jiných kritérií než podle ceny, nebo možnost jejich seskupení podle místa odletu nebo pˇríletu. Dále ruzné ˚ filtry vyhledávání, kdy by uživatel mohl napˇríklad vyhledat pouze lety o víkendu. Urˇcitˇe by byla vhodná i možnost pˇresouvání kruhu po mapˇe pomocí gest, podobnˇe jako je tomu pˇri zmˇenˇe jeho velikosti. Spoleˇcnost Skypicker rovnˇež stále rozšiˇruje své služby a bude jistˇe zapotˇrebí pˇridávat do aplikace novou funkˇcnost korespondující s funkˇcností webové aplikace. Vše tedy spˇeje k tomu, že se se mi podaˇrí uzavˇrít se Skypickerem dohodu o další spolupráci. Nápadu˚ na vylepšení a rozšíˇrení funkˇcnosti pro maximální spokojenost uživatelu˚ je mnoho a osobnˇe doufám, že touto bakaláˇrskou prací muj ˚ vývoj aplikací na Android s tematikou vyhledávání a nákupu letenek nekonˇcí.
36
Literatura [1] Ian F. Darwin. Android Cookbook (angl.). O’Reilly, 2012. [2] FeedIT.cz. Skypicker nabízí levné letenky po Evropˇe už témˇerˇ rok. [online] [cit. 2013-05-13] Dostupný z WWW: . [3] David Flanagan. O’Reilly, 2011.
JavaScript: The Definitive Guide (angl.).
[4] Google, Inc. ADT Plugin (angl.). [online] [cit. 2013-0513] Dostupný z WWW: . [5] Google, Inc. Android Developers (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: . [6] Google, Inc. Android SDK (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: . [7] Google, Inc. Application Fundamentals (angl.). [online] [cit. 201305-13] Dostupný z WWW: . [8] Google, Inc. Google Maps Android API v2 (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: . [9] Google, Inc. Google Play Services (angl.). [online] [cit. 2013-0513] Dostupný z WWW: . [10] Google, Inc. Keeping Your App Responsive (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: . [11] Google, Inc. MapView Tutorial - Google Maps Android v1 API (Deprecated) (angl.). [online] [cit. 2013-05-13] 37
4. A PLIKACE S KYPICKER Dostupný z WWW: . [12] Google, Inc. Setup Google Play Services SDK (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: . The AndroidManifest.xml File (angl.). [13] Google, Inc. [online] [cit. 2013-05-13] Dostupný z WWW: . [14] Dan Graziano. Jelly Bean now found on a quarter of Android devices – sort of (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: . [15] Richard L. Hutchison. Table of Latitude and Longitude equivalents (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: . [16] Stack Exchange Inc. Stack Overflow (angl.). [online] [cit. 201305-13] Dostupný z WWW: . [17] Reto Meier. Proffesional Android 4 Application Development (angl.). John Wiley Sons, Inc., 2012. [18] Mark L. Murphy. The Busy Coder’s Guide to Advanced Android Development (angl.). CommonsWare. [19] Bc. Tomáš Novotný. Mobilní mapová aplikace Iris pro Android. Diplomová práce, Masarykova Univerzita, Fakulta Informatiky, 2012. [20] Jules (pˇrezdívka). Answer: Why does casting net.simonvt.numberpicker.NumberPicker to android.widget.NumberPicker work? (angl.). [online] [cit. 2013-05-13] Dostupný z WWW: .
38