Média Ismeretek | Tanulmányok, esszék » Teket Dávid - Windows Phone

Alapadatok

Év, oldalszám:2014, 43 oldal

Nyelv:magyar

Letöltések száma:64

Feltöltve:2014. május 23.

Méret:1 MB

Intézmény:
-

Megjegyzés:

Csatolmány:-

Letöltés PDF-ben:Kérlek jelentkezz be!



Értékelések

Nincs még értékelés. Legyél Te az első!


Tartalmi kivonat

Tartalomjegyzék 1. Előszó - Miért éppen Windows Phone?5 1.1 A projekt koncepciója6 1.2 Felhasznált technológia 7 1.3 Probléma megközelítése 8 1.31 API kulcsok előkészítése 8 1.32 A projekt létrehozása sablonból10 2. Az alkalmazás modellje 12 2.a +App (inicializálás) 13 2.b +MainPage 14 2.c +MainViewModel14 2.d +App (finalizálás) 14 2.e +MainPage - MEGJEGYZÉS14 2.f +MainViewModel(konstruktor) 14 2.g +DataQuery 14 2.h +GPS 15 2.i +MainPage 15 2.j +GPS (visszatérés) 15 2.k +DataQuery 15 2.l +MainViewModel (visszatérés)15 2.m VenueView:INotifyPropertyChanged (megszólítjuk a Nézetet)15 3. Adatmodellek 16 4. Funkciók, algoritmusok és forráskódok 1 rész 19 4.1 MainPagexaml 19 4.1a A "MyMap" vezérlő 17 4.1b A "SearchBox" és a "SearchButton" vezérlők szerepe20 4.1c A "MainLongListSelector" szerepe20 4.1d Megjegyzés a MainPage osztállyal kapcsolatban21 4.2 A MainViewModel osztály22 4.2a Kollekciók és

tulajdonságaik22 4.3 A DataQuery osztály 23 1 4.3a A DataQueryForVenueViewModel metódus24 4.3b A TipsFromVenueData metódus26 4.4 A GPS osztály26 4.4a Az UpdateMyMap metódus26 4.5 A MainViewModel betöltői27 4.5a A LoadVenues metódus27 5. Funkciók, algoritmusok és forráskódok 2 rész29 5.1 DetailsPagexaml 29 5.1a A "TipLongListSelector"29 5.1b A "DetailsPageTitle" adatforrása30 5.1c További TextBlock-ok30 5.1d Megjegyzés a DetailsPagexamlcs osztályával kapcsolatban31 5.1e A "saveBarButton" funkciója32 5.2 UserFavouritesxaml32 5.2a A "FavList" szerepe32 5.2b A UserFavouritesxamlcs, a DetailsPagexamlcs és a MainPagexamlcs kapcsolata.33 5.2c ReSaveFavourites és IsolatedStorage35 5.2d ReLoadFavourites35 5.2e LoadFavourites 35 5.2f Az OnNavigatedTo (folytatás)36 5.2g Kedvencek törlése 36 6. Az alkalmazás tesztelése37 6.1 Automatikus tesztek 38 6.2 Teljesítménytesztek38 6.3 Mennyi CPU erőforrást fogyasztanak a saját

függvényeim?41 6.4 Manuálist tesztek41 7. Publikáció és utószó: hogyan tovább?41 7.1 Microsoft Dev Center 41 7.2 Összefoglaló 42 2 Szakdolgozat City Trends app Írta: Teket Dávid Computer School Szakképző Iskola - szoftverfejlesztő szak 2014. Budapest A projekt forráskódját közzétettem a GitHub-on 3 https://github.com/zaug/city trends app 4 1. Előszó - Miért éppen Windows Phone? Amikor tavaly November 6-án kilátogattam a Microsoft Magyarország szervezésében megrendezett Windows 8.1 fejlesztői konferenciára, olyan inspiráló szakemberek előadásán volt szerencsém részt venni, ahol az ökoszisztémára való fejlesztés kérdései mellett számos technológiai innováció is terítékre került. Jelen voltak azok a szakemberek is akik a Windows Phone fejlesztéséhez szükséges könyvet írták, nekünk magyar fejlesztők nek, és amely tudástárat tanulmányozva ez a dolgozat megszülethetett. Köszönettel tartomzom nekik, a

Channel9 mentorainak, és "könnyen emészthető" oktatóvideóiknak. Tehát dolgozatom tárgya tulajdonképpen az okostelefonokra történő alkalmazásfejlesztést veszi át, ezen belül választott platformként a Microsoft Windows Phone (8.0 verziószámú) operációsrendszerét. Itt a fejlesztés hatékony, mindemellett a használt technológia is rugalmas, biztonságos, és rendkívül sokoldalú. Motivációm onnan fakadt, hogy létrehozzak valamit, amit könnyű kezelni, "párfunkciós", és mégis: egy dinamikus adatbázissal áll kapcsolatban, és még hasznos is lehet. Ráadásul kellően modern technológiából építkezik, mobilis környezetben. Ezeknek az igényeknek a platform tökéletesen megfelel: könnyedén építhetünk reszponzív, látványos felületeket, ráadásul ismerős .NET környezetben Be fogom mutatni projektem megtervezésének, és elkészítésének lépéseit, megközelítéseit, megfontolásait a papír alapú tech-vázlattól

kezdve az Store-ban publikálható app-ig. 5 1.1 A projekt koncepciója Miután sok ötletelgetés (brainstorming) után végül kitaláltam, hogy mit is fog tudni az alkalmazás, össze is foglaltam a fő irányvonalakat:  Felhasználom a telefon GPS-ét,  Kapcsolatot létesítek a "felhővel"  Geolokációs adatokat fogok lekérdezni, és ezeket feldolgozni,  Tippeket, címeket, elérhetőségeket, távolságot stb. jelenítek meg,  Lehetőséget adok a felhasználónak a keresésre, és hogy elmenthessen helyeket, kedvencnek jelölhesse azokat. Majd készítettem egy viszonylag egyszerű tech-vázlatot: Látható, hogy a képen megjelöltem azokat az elemeket, amelyekhez később implementálnom kellett a megfelelő funkciókat. Tehát a kezdőoldalunk (MainPagexaml) tartalmaz:  Fejléceket: itt jelenítem meg az app és az oldal nevét.  Térképészeti vezérlőt: a felhasználó pozícióját veszi alapul.  Szövegbeviteli

vezérlőt plusz a keresést indító gombot: segítségükkel tudunk célzott keresést végrehajtani.  Az alkalmazás sávot, ami két gombot tartalmaz, az egyik a kedvencekhez navigál, a másik az alkalmazás információkhoz.  Rács elrendezésű listát amin a találatok információit jelenítjük meg. Minden egyes csempe a rácson tapintható lesz, tehát segítségükkel navigálunk át a részleteket összesítő (DetailsPage.xaml) oldalra 6 Itt részletesebb információt kaphatunk a kiválasztott csempén prezentált összefoglalóról: Az oldal neve a helyszín nevére frissül, alatta megjelenítődnek további információk, mint például a cím, a tőlünk mért távolság, a tippek száma, és a forgalom is.  Helyet kapott egy lista is, ami megjeleníti a tippeket, és azok íróit is.  Az oldal alján egy gombot helyeztem el, amivel kedvencnek jelölhetjük a helyszínt. Ezzel a gombbal átnavigálunk a kedvencekhez (UserFavourites.xaml),

ami egy olyan speciális listát tartalmaz, amelyen egyszerre több elem is kijelölhető , ezáltal lehetővé téve a felhasználónak, hogy elemeket töröljön a kedvencek közül. Természetesen nem adtam teret fölösleges öncélú és statikus látványelemeknek, mivel a hangsúly a felhasználói interakción és a dinamizmuson van. Most, hogy madártávlatból ismertettem a koncepciót, ideje megismerni a részleteket. 1.2 Felhasznált technológia  Fejlesztői környezet (IDE): o  Programozási nyelv: o   C# (.NET 45-ös keretrendszerrel) Kiterjesztett alkalmazásfelület leíró nyelv: o  Microsoft Visual Studio Express 2012 for Windows Phone XAML (eXtended Application Markup Language) Harmadik féltől származó könyvtárak (reference library-k): o Json.NET o Coding4Fun Toolkit o Windows Phone Toolkit o Http Client Library Geolokációs adatok: o Foursquare API 7 1.3 Probléma megközelítése Miután tisztán kijelöltem a

megvalósítandó célokat (1.2) a következő lépés a jó kiindulási alap megválasztása volt Először is kellett egy olyan adatbázis, amelyez kapcsolódhatnék, hogy megvalósíthassam a lekérdezéseimet. Kiderítettem, hogy léteznek olyan alkalmazás programozási interfész kibocsájtók (API exposers) akik rendelkeznek nyilvánosan elérhető API kkal. Tehát egy egyszerű HTTP GET metódussal és egy Query String-gel hozzáférhetek azokhoz az adatokhoz, amik engem vagy a felhasználómat érdekelhetik. Miután kiválasztottam a kedvenc geolokációs szolgáltatásokat nyújtó webhelyemet (foursquare.com) és átböngésztem az API reference docs-t, már tudtam mit kellett tennem és egy problémát ki is húzhattam a tennivalólistáról. 1.31 API kulcsok előkészítése Ahhoz, hogy egy ilyen típusú hívást igénybe vehessünk a jelen protokoll szerint szükségünk lesz titkos és kliens azonosítókra, és mivel én nem használtam private endpoint-ot (olyat,

amihez a rendszerbe regisztrlált felhasználót be kell jelentkeztetni aka.: autentikációs eljárást), így nem kellett OAuth2 Token-t használnom (ezeket használják 3rd party alkalmazások amik pl. a Facebook-on keresztül jelentkeztetik be felhasználóikat) Először is regisztráltam az alkalmazást a developer.foursquarecom-on, és kaptam egy Client ID-t, és egy Client Secret-et: Lássuk milyen API Endpoint hívásokat valósítok meg: a. Search Venues API: Visszatérési értéke pl. a helyszín címe, távolsága Keresést is támogat Vegyük a Request URL-jének felépítését (továbbiakban QueryString-nek hívom): QueryString = https://api.foursquarecom/v2/venues/search? // Az Endpoint típusát jelöli v = 20131016 // API verzió. &ll = 47.514592%2C19043463 // A földrajzi szélességet & hosszúságot a telefon GPS-e határozza meg &limit = 100 // Hány találatot akarunk megjeleníteni? &intent = checkin // A lekérdezés célpontját jelenti.

&radius = 100 // Azt a körzetet jelenti (méterben) amelyen belül keresünk. &client id = MEEMBBKDBZOVGYOZXTRG2PTQ0Q5GKMV3A2XJIDCDVMFF4EQ5 // A kliens azonosítóm. &client secret=KII3G1GW3ONBWG2W5FH1NJQZTT055A1C4H0DJWJCA3N1B5WU // Titkos azonosítóm. 8 Tesztelésre az Apigee konzolfelületét használtam: A teszt alatt át tudtam tanulmányozni a QueryString felépítését, és a hívás visszatérési értékét ami egy JSON formátumú adatstruktúra. Ezt C#-on belül osztályoknak, és azok adattagjainak feleltetjük meg Én a következő adattagokkal (attríbútumokkal, típusokkal) dolgoztam:  helyszínek neve,  helyszínek azonosítója,  címe,  városa,  kategóriája,  statisztikái Mivel a tippeket is le akarom kérdezni, ezért szükségem lesz a helyszín ID-kra is. (Erről később bővebben lesz szó) Tips from a Venue API: Visszatérési értéke: tippek, dátumok, felhasználónevek, stb. Ahhoz, hogy működjön a

lekérdezés, szükség lesz a helyszín ID-kra. Most csak egy részét írom le a QueryString-nek, mert a többi paraméter teljesen megegyezik az előző pontban felsoroltakkal: QueryString = https://api.foursquarecom/v2/venues /4e7b73c9b8f7e8cf47066c47 // Helyszín azonosító (minta). /tips? // Az Endpoint típusát jelöli. v=20131016 // API verzió. &sort=popular // Rendezési feltétel (pl. a legnépszerűbbeket adja találatként stb) &limit=100 // Azt a körzetet jelenti (méterben) amelyen belül keresünk. 9 Újabb példa a hívás eredményére: 1.32 A projekt létrehozása sablonból Amikor egy nagy komplexitású feladatnak vágunk neki, érdemes elidőzni a rendelkezésünkre álló sablonok tárházában. Nekem jó kiindulási pontot jelentett a Windows Phone Databound Projekt sablon ami közvetlenül elérhető a Vis ual Studio-ból. Ebben a pontban leírom, hogy pontosan miért volt szükség erre a sablonra XAML: Miután a Visual Studio-ban elérhető

sablonokat összevetettem a saját elképzeléseimmel, a legjobb megközelítést a Windows Phone Databound Project Template jelentette, amiben rögtön észrevettem egy hasonlóságot, ez pedig a LongListSelector vezérlő, amihez Design (szerkesztési, nem futásidejű!) időben tartozik Design adat is (a project solution Sample Data mappájában találjuk). Így nagyon egyszerű dolgom volt design időben megtervezni az app layout-ját Ez a tulajdonság végtelenül hasznos a fejlesztés korai szakaszában, például amikor nincs szükség valós adatra (online data), hanem csak a vezérlők megjelenését szeretnénk azoknak megfelelően módosítani- és, hogy ne kelljen minden egyes változtatás esetén újrafordítani-emulálni a projektet, a tervezőfelület automatikusan változik, hála a design adatnak. A XAML-be mélyen be van ágyazva az adatkötés (Data Binding) technológiája. Ha valamit megváltoztatunk az egyik helyen, a változás azonnal megjelenik a másik helyen

is, ezzel konzisztenssé téve mind a fejlesztés menetét, mind az alkalmazás működését. A design adatot úgy módosítottam, és több új XAML adatfájlt is hozzáadtam a projekt későbbi fázisaiban, hogy pontosan azt a vizuális megjelenést képezze le amit a lekérdezésből állítok elő. 10 Íme egy példa (ezt a képet az UserFavourites.xaml-ről készítettem: 1. Az UserFavourites.xaml felhasználja a d:DataContext (jelentése: prefix:névtér) által mutatott statikus XAML fájlt, így hozzáfér annak tagjaihoz. 2. Vegyük észre az UserFavourites SampleData.xaml-ben a gyökér (root) object-et: MainViewModel, ami nem más, mint a projekt forrásfájlai között megtalálható MVVM implementáció, tehát a MainViewModel.cs forrásfájl tartalmazz a specifikus kollekciót, ami pedig a megfelelő nézetre (View) mutat. Jelen esetben ez a FavouriteView.cs 3. Miután kiválasztottuk a Modellt, annak kollekcióját, lehetségessé válik az attríbútumok

megnevezése és DESIGN időben történő értékadása. Fontos, hogy ezek az értékek Runtime alatt nem jelennek meg, mert azok az MVVM implementációjából származnak! 4. Ha átírunk egy attríbútum értéket, a felületen AZONNAL megjelenik a változás. MVVM pattern: Ha indítunk egy Windows Phone Databound sablont, láthatjuk, hogy már implementálta az MVVM (Model-View-ViewModel) tervezési mintát, tehát a rendelkezésre álló adatok futási időben (Runtime) történő kivezetése megoldott. Ezt kellett a későbbiekben újraírnom, de ebben a filozófiában. Továbbá minden egyes nézet (View) megvalósítja az INotifyPropertyChanged interfészt, ami tulajdonképpen egy értesítési mechanizmust jelent a Model -ben lévő kollekció ObservableCollection<View> irányában. Történetesen ha egy property megváltozik, akkor a felület frissül Mi ebben a kontextusban azonban nem fogjuk teljes mértékben kihasználni ezeket az adottságokat, viszont végig

jelen lesz a forráskódban. 11 Az alábbi UML diagramm által ismertetném projektem MVVM & INotifyPropertyChanged koncepcióját (az attríbútumokra a későbbi fejezetekben térek ki): 2. Az alkalmazás modellje Szakdolgozatom az alkalmazás mechanizmusát tárgyaló további részét a kód szándékolt végrehajtási ütemében dokumentálom. Amikor ezt írom debug üzemmódban lépkedek végig a kódon futási időben, töréspontok segítségével, hogy PONTOSAN a kód végrehajtási menete szerint dokumentáljak, így az olvasónak is érthető lesz a kód logikája, és a hívások sorrendje is. Az átfogó kép kedvéért több UML osztálydiagrammot is készítettem, ezeket később a kontextusnak megfelelően ábrázolva mutatom majd be. A következő ábrán látható az alkalmazás osztályhierarchiája Néhány fontos megjegyzés: 12  A diagramm az alkalmazás inicializált állapotát közvetíti,rámutat az osztályok közötti kapcsolatokra,

függőségekre,  a szaggatott vonalak az osztályok közötti felhasználási irányt prezentálja,  a többi nyíl az alkalmazás inicializált (tehát még interakció nélküli) hívásainak irányát mutatja,  minden egység fejlécében az osztály neve szerepel,  a + jelölés "public", a - jelölés "private", a # jelölés "protected" megfelelője,  az egységek második sorában az adattagok láthatóak,  a harmadik sorban pedig a tagfüggvények jelennek meg. Az alkalmazás inicializálásának üteme (Code flow) UML-en ábrázolva: a. + App 1. Inicializációs állapot. 13 2. Beállítódnak az alkalmazás egyes tulajdonságai, mint pld. az XAML komponensek inicializációja, a kapott objektumgráf leképezése (RootFrame parsing), a telefonspecifikus, nyelv specifikus, debug-specifikus, és kivételkezeléssel foglalkozó alapértelmezései. 3. Megtörténik a felületen megjelenő adatokhoz szükséges

MainViewModel példányosítása. 4. Felület előkészítése (RootFrame). 5. Beállítódnak a nyelvi tulajdonságok (olvasási irány). 6. Meghívódik, ha alkalmazásunkat először indították el. b. + MainPage 7. Adattag inicializálás, és Komponensek előkészítése, MainViewModel példány létrehozása. 8. Létrejön az oldalsáv, és beállítódnak a tulajdonságai. c. + MainViewModel 9. Meghívódik a MainViewModel konstruktora, itt jönnek létre az ObservableCollection<Type> példányok. Visszatérünk a MainPage-re, és beállítjuk a ViewModel-t az oldal kontextusának. d. + App 10. A vizuális elemek leképezése megtörténik 11. Ha újraindították az alkalmazást visszaállítja a vermet (BackStack) e. + MainPage - MEGJEGYZÉS: Ettől a ponttól kezdve már saját, általam megvalósított funkciók előtöltését végzi a Windows Phone Runtime Engine. Ezeket a funkciókat & algoritmusait kóddal együtt részletesen ismertetem a 4

fejezettől. 12. A navigációs metódus betölti az adatokat (ha van keresési kulcsszó, akkor aszerint) a ViewModel -be, tehát meghívja +MainViewModel LoadVenues tagfüggvényét. f. + MainViewModel 13. Meghívódik a konkrét LoadVenues tagfüggvény, ami helyadatokat tölt be a Venues kollekcióba A függvény törzsében létrejönnek az állapotváltozók, a VenueModel, DataQuery, GPS, és List<VenueData> példányok amik a szükséges adatokat szállítják majd a program megfelelő részeibe. g. + DataQuery 14. Beállítódnak az API specifikus tárolók (segítségükkel fog működni a lekérdezés) Visszatérve a + MainViewModel-hez, meghívódik az UpdateMyMap metódus. 14 h. + GPS 15. Példányosítja a DataQuery, GeoLocator, ProgressIndicator, GeoPosition osztályokat A függvény törzsében meghívódnak azok tagfüggvények, amelyekkel az app képes lesz meghatározni a földrajzi szélességet- és hosszúságot. 16. Az előbb tárgyalt Geolokációt

meghatározó metódus híjva segédfüggvényként: mindössze annyi a dolga, hogy kijelezzen egy oldalsávot a telefon kijelzőjén, tudatva a felhasználóva l, hogy a telefon keresi a GPS pozíciót. i. + MainPage 17. Mivel az előbb taglalt lekérdezések aszinkron típusúak (így ez a vezérlési típust engedélyezi a futtatómotor), tegyük fel, hogy a telefon most tudta meghatározni a helyzetét, így a vezérlés visszaugrik a MainPage osztály adott kódjára. Itt a már felhasználható koordináták alapján képes beállítani a Map vezérlő középpontját, és a Zoomolási távolságot. j. + GPS (visszatérés) 18. A lokációs adatok kinyerése sikeres volt, így a GPS példányunk már át fogja tudni adni a helyszínadatokat, az őt meghívó LoadVenues metódusnak. k. + DataQuery 19. A LoadVenues meghívja a DataQueryForVenueViewModel tagfüggvényét: visszatérési értékeként betölti a VenueModel példányba az adatokat. Ezek az adatok (vagy találatok) GPS

pozíciótól, és keresési kifejezéstől függnek. A metódus meghívja a QueryString létrehozásához szükséges segédfüggvényt: 20. Paraméterként tartalmazza az összes olyan szükséges változót (és konstanst) amiből előállíthatóvá válik egy használható QueryString. Ezt fogjuk használni az összes Search Venues API hívásnál Lásd 131 21. A metódus aszinkron kapcsolatot létesít az API-val, és lekérdezzük az adatokat (JSON formátumú adatcsomagot kapunk). Ezután a kapott JSON struktúrát deszerializáljuk és betöltjük a VenueModel egy példányába, ezt a példányt adjuk át a LoadVenues metódusnak, mint visszatérési értéket. l. + MainViewModel (visszatérés) 22. Mivel a lekérdezett adatok nagy részére nincs szükség, ezért eldobjuk a nagy részét, vagyis egy részhalm azát betöltjük egy butított osztálypéldányba. Most már előkészíthető minden állapotváltozó, és hozzáadható a Venues kollekció egyes VenueView

példányainak (minden nézetfrissítéskor, vagy új adatok érkezésekor új példányok jönnek létre a VenueView-ből, és mivel ezek a View-ek (nézetek) INotifyPropertyChanged interfészen keresztül lettek megvalósítva az ObservableCollection<Type> automatikusan értesítve lesz, ha akár csak egy példány is frissül, vagy új jön létre. Az ObservableCollection<Type> ezt riportálja a LongListSelector vezérlőnek, és a felület frissülni fog. m. VenueView : INotifyPropertyChanged (megszólítjuk a Nézetet) 23. Amikor új View példány jön létre, a privát tagok automatikusan felülíródnak, minden egyes privát tag módosulásakor, a setter (beállító) NotifyPropertyChanged("attribútum") eseményt dob. Ezt a típusú eseményt a NotifyPropertyChanged kezelője kapja el, aki a k. pontban leírtak szerint végzi a dolgát 15 Alkalmazásom gyakorlatilag 23 lépés alatt előkészült a fogadtatásunkra. (Ha minden rendbe n lezajlott,

máskülönben kivételt dob). Most, hogy minden komponens a helyén van, elkezdhetünk megvizsgálni őket közelebbről,! Ám mindenek előtt ismerjük meg magukat az adatmodelleket amikbe a JSON adatainkat deszerializáltuk! A következő UML grafikonokon azok felépítéseit ábrázolom. 3. Adatmodellek A 2. fejezetben bemutattam az alkalmazás modelljét, megfigyeltük komponenseit (közel sem mindet), azok hívási környezetét. Ám, hogy működjön, összhangba kell helyezni az adatok modelljeivel Lássuk a megközelítést: Ha visszatekintünk az 1.31a pontra, akkor tettem egy említést az Apigee konzolfelületéről Egy ilyen tipusú tool hatékony módja annak, hogy célirányosan kipróbálhassunk egy ilyen API -t. Megjegyezném, hogy az ebben az iparágban különösen értékes a rendelkezésre álló, fejlesztési munkálatokat segítő, és meggyorsító eszközök palettájának ismerete. A JSON adatokat prezentálandó osztályhierarchiák (modellek) megalkotása

nehéz és fáradtságos munka tud lenni. Szerencsére, egy kis keresgélés után megtaláltam a megfelelő eszközt a json2csharp.com webhelyen (JSON adatokat konvertál C# osztályokba), mint ahogy az ábra is mutatja: Miután éltem a lehetőséggel, már csak a projekt körülményeinek megfelelően kellett átszabni ezt-azt, például egyszerűsített Model -> Group -> Data irányt választottam, és a típusokhoz megfelelően választottam meg a neveket pl. VenueData. Vegyük észre, hogy a teljes model használatba vétele erőforrásigényes, tulajdonképpen csak a teljes megfeleltethetőség, és a deszerializációs metódusok hibátlan működtetése miatt kényszerültem a teljes modellre. Ugyanakkor mindig csak a halmaz olyan speciális részhalmazával dolgoztam a forráskód további részeiben, amit az adott funkciók implementálásához feltétlenül szükségesnek tartottam. 16 Lássunk egy példát a lekérdezett JSON adatstruktúra C# adatmodelljeként

történő reprezenálására: Kísértetiesen hasonlít egy relációs adatbázishoz: az entitásokat gyűjteményekként kezeljük, az attríbútumokat pedig azok részeiként. Ezzel szemben alkalmazásom nem fog ilyet használni Ennek kompenzációjára bevezettem egy olyan funkciót ami a telefon IsolatedStorage-ére (izolált tárterület) képes fájlokat menteni, és a korábbi állapotát visszaállítani az alkalmazásnak, még ha a felhasználó ki is lép abból, vagy újraindítja a telefont. 17 Minden készen áll. Ismertettem a hierarchia felépítését, a lekérdezésekhez szükséges osztályainkat és metódusainkat, az adatmodelljeinket, és magát a projektsablont. A következő részben már CSAK azokat a funkcionalitásokat - ezekkel együtt a felhasznált algoritmusokat - mutatom be, amelyeket saját magam implementáltam. A projekt többi tulajdonságaira (kivéve a XAML deklarációkat - az egyéni módosításokról ugyanis teszek említést) már

kitértünk a 2. fejezetben (az alkalmazás modellje című részben). 18 4. Funkciók, algoritmusok és forráskódok 1 rész Kezdjük az alkalmazás logikájával: amikor a felhasználó megnyitja az alkalmazást a 2. fejezetben leírt folyamat szerint hajtódnak végre bizonyos kódblokkok (ilyenkor inicializál a Windows Phone Runtime Engine). Tehát alapértelmezetten a főoldalt látjuk (MainPage.xaml) Lássuk részletesen, hogy mi, hogyan, és miért működik úgy, ahogy működik. 4.1 MainPagexaml a. A "MyMap" vezérlő A főoldalon elhelyeztem egy Map komponenst, ami amellett, hogy vizuálisan feldobja az alkalmazás kinézetét, a felhasználó földrajzi helyzete alapján állítja be saját nézetét, lássuk a XAML szintaxist: Látható, hogy a komponens a maps: névtérből származik, és deklaratívan megadtam neki a vizuális megjelenést befolyásoló tulajdonságokat. Vegyük észre a 84-es sorban a Name attríbútum értékadást Erre a névre

hivatkozok a mögöttes kódból (mint számos más interaktív vezérlő esetén), hogy megváltoztassam futási időben annak SetView tulajdonságait: Miután példányosítással létrehoztam egy Geolocator típusú objektumot (a Windows.DevicesGeolocationGeolocator névtérből származik), meghívtam a GetGeoPositionAsync tagfüggvényét, beállítottam a késleltetési időt, és átadtam a tartalmát egy GeoPosition típusú objektumnak (Windows.DevicesGeolocationGeoposition) Majd eltároltam annak Coordinate.Latitude (hosszúság) és CoordinateLongitude (szélesség) tulajdonságait egy GeoCoordinate típusú objektumban (System.DeviceLocationGeoCoordinate) Itt jön képbe a XAML komponens tulajdonságának beállítása is (property) ami történetesen a GeoCoordinate típusú változóm értéke alapján állítja be a térkép középpontját. Vegyük észre a függvény visszatérési típusa előtt álló async kulcsszót, ami futási időben annyit jelent, hogy a kód

végrehajtása halad tovább, mindaddig amíg a kívánt változót fel nem akarjuk használni ( aminek await kulcsszóval jelölt utasításokkal adtunk értéket). Mindezt azért, hogy felületünk válaszképes, reszponzív legyen Ha nincs feltöltve, és használni kívánnánk a változót, a kód végrehajtása megáll, esetleg kivételt dob. 19 b. A "SearchBox" és a "SearchButton" vezérlők szerepe Miután a keresési funkció implementálása mellett döntöttem, el kellett helyeznem az oldalon egy TextBox -ot, mellette pedig egy Button vezérlőt. A gomb megnyomására lezajlik a Click esemény, ami az oldal mögöttes kódjában lévő SearchButton Click eseményt szólítja meg, és lekérdezi a TextBox-om tartalmát: Lássuk a 44-es sort: megjegyzésként beírtam, hogy defenzív kód. Mit is jelent ez? Mi Http webrequest-ekkel fogunk dolgozni a továbbiakban, azaz egy kód része lesz, amit egy szerveroldali elemzőnek kell értelmeznie. Viszont

ha a felhasználó (szándékosan vagy nem) olyan kulcsszót/karaktert üt be ami elronthatná az URL-emet (akár ékezetes betűt): akkor a lekérdezésem már nem működne. Ezért hívom meg a SearchBox Text tulajdonságára a HttpUtilityUrlEncode tagfüggvényt. A 45-ös sor új lekérdezést indít, és átadja a MainViewModel osztály LoadVenues metódusának az előbb beírt paramétert - de annak működéséről majd később is szó lesz. Az osztályban deklaráltam egy string típusú searchValue változót is: ő fogja tartalmazni a keresési kulcsszót. c. A "MainLongListSelector" szerepe Ezúttal egy igen komoly, és összetett vezérlőt mutatok be: a LongListSelector -t. Lássuk a vezérlő XAML anatómiáját: A LongListSelector egy végteleníthető (tehát amíg van találat, görgethetünk lefelé) listát prezentál. Erre a vezérlőre - a mögöttes kódból - "MainLongListSelector" néven hivatkozok. Vizuális megjelenés szempontjából Grid

(rács) megjelenésűre állítottam be. Továbbá három igen-igen fontos szerepe van:  Megvalósítja az ItemsSource attríbútumot, tehát adatkötést alkalmaz (Data Binding, vagy Binding Syntax). Jelen esetben a Venues kollekcióhoz kötöm ezt a felületi elemet  Van egy SelectionChanged attríbútuma, a kiválasztott elem tulajdonságait ábrázolja (ennek előnyeit az oldalak közötti navigáláskor használtam ki), majd a mögöttes kódból a MainLongListSelector SelectionChanged eseményt szólítja meg.  Végül van egy ItemTemplate attríbútuma, ami nem más mint egy erőforráshoz kötést valósít meg. Ez az erőforrás részben az adott komponens (LongListSelector) vizuális elrendezésének (layout) definícióit írja le, részben azokat a mezőket amelyekből adatot köthetünk a kimenetre. Igen, köthetünk, mert már meghatároztuk a felhasznált kollekciót. Foglalkozzunk most az ItemTemplate attríbútummal! Nevezetesen a MainPageTile

definícióra hivatkozik: 20 Vegyük át az erőforrás felépítését: a 19-es sor jelzi a fordítónak, hogy erőforrásról van szó, nem felületi elemről. A 20-as sorban meghatároztam egy DataTemplate (adatsablon) kulcsot, hogy egy XAML dokumentumból, vagy akár az egész projektből hivatkozhassak erre az erőforrásra (újrafelhasználhatóság). Az egész LongListSelector (rács) elem felépítését pedig 1-1 StackPanel-be (verembe) ágyazott TextBlock adja. Ezek a TextBlock -ok ugyanúgy adatkötést valósítanak meg a Venues kollekció specifikus mezőivel. Itt jelennek meg a Design / Runtime adatok Most pedig térjünk vissza a vezérlő MainLongListSelector SelectionChanged eseménykezelőre. Lássuk a mögöttes kódot: Miután a csempék lesznek a részletek belépési pontjai is, itt valósítottam meg a NavigationService.Navigate osztály metódusát, ami egy URI-t vár (egy olyan elérési útvonalat ami alapján megtalálja a kívánt XAML oldalt). Ezt az

URI-t egy segédváltozóval valósítottam meg, ami jelen esetben a queryString. A 64-es sorban figyeljük meg, hogy először beírtam a karakterliterált (hard-coded), majd az egyes záradékokba pl.: selectedItem={0} behelyettesítettem a MainLongListSelector kiválasztott elemét ami alapértelmezésben egy object típus, de az as kulcsszóval explicit módon kényszeríthettem a fordítót, hogy VenueView objektumpéldányra kasztolja, és annak is az .ID tagját adja vissza Hogy miért volt szükség a ?-jelölésre? Így megtehetem közvetlenül a másik oldalon (DetailsPage.xaml), hogy lekérdezzem a NavigationContext.QueryString["kulcs"] metódus által a kulcsot reprezentálandó elemet, és, hogy felhasználhassam azt A továbbiakban ugyanis szükség lesz az oldalak közötti adatmeg osztásra is. d. Megjegyzés a MainPage osztállyal kapcsolatban Az oldal C# kódjában lévő MainPage osztály parciális, és PhoneApplicationPage interfészt valósít meg,

tehát a fordító összeszerkeszti azt (parsing, rendering, linking), a XAML-ben deklarált osztálypéldányokkal.Hogy lehetséges ez? Mivel a XAML egy deklaratív jelölőnyelv, természetesen OOP alapokon dolgozik, tehát ha egy TextBox -ot akarok létrehozni, elegendő leírnom egy sorban, és ő automatikusan elkészíti hozzá a megfelelő példányokat, beállítja a tulajdonságokat stb. Ez a XAML lényege Elszeparálja a felületet leíró kódot a mögöttes, logikai működéstől, és az eredmény SOKKAL TÖMÖREBB, "önleíró" (self explaining) kód. Összeszerkesztés után így jöhet létre az a köztes kód (CIL - Common Intermediate Language) amit a JIT (Just In Time) majd feldolgoz, és átad gépi kódként a CPU -nak. Most pedig fókuszáljunk egy kicsit arra, hogy alapértelmezetten (tehát explicit keresés nélkül), honnan jönnek az adatok? Hogy-hogy megjelennek egyáltalán? Milyen kód végzi el ezt a feladatot? A választ az oldal

alapértelmezés szerinti OnNavigatedTo eseménykezelője adja, amit maga a Windows Phone Runtime Engine indít el (illetve ez a tulajdonság a project properties -ben is konfigurálható, hogy az 21 app indulásakor melyik oldal jelenjen meg elősször): A fenti kód megkérdezi, hogy be van-e töltve az adott nézet. Ha nincs betöltve, betölti az adott View-t (vegyük észre a searchValue paramétert!). A továbbiakban a betöltő metódusok felépítését és logik áját fogom részletesen ismertetni 4.2 A MainViewModel osztály Ebben az alfejezetben az adatok kezelésének lelkét, a MainViewModel osztály működését mutatom be, további alfejezetek során, kitérek minden általam megvalósított segédfüggvényre, eljárásra, ad atkezelési módszerre. Ezt az osztályt úgy tekinthetjük mint egy modellt, ami komplex kollekciókat foglal magába, közvetlen kapcsolatban áll a XAML lel, megvalósítja az INotifyPropertyChanged interfészt, meghívja az adatok

eléréséért és feldolgozásáért fele lős segédfüggvényeket (amik további osztályok részeit képzik) és elvégzi az adatok betöltését a megfelelő nézetekbe. a. Kollekciók és tulajdonságaik Nézzük meg közelebbről azokat a konténereket, amik megjelennek az adott XAML ItemsSource -aként: Elősször is látható, hogy minden ObservableCollection<Type> public láthatósági módosítóval van ellátva. Miért is? Mivel más osztályokon keresztül szeretnénk hozzáférni az adattagokhoz, így egy ilyen fontos szerepet betöltő adattag (kollekció) nem kaphat privát jelölést. Hogy bebizonyítsam, lássuk a hívási hierarchiát: 22 1. Lekérjük a Venues kollekció hívási hierarchiáját. 2. Egy nagyon hosszú listát kapunk, de minket most csak az érdekel, hogy kik azok a külső osztályok, akik hozzá akarnak férni a kollekciómhoz, és miért. Például látjuk, hogy a City TrendsDetailsPage OnNavigatedTo eseménykezelője felhasználja.

3. Kibontva a gyermek elemet, látható, hogy egy DataContext két helyen is használatba veszi. (Call Sites ablak) De miért veszi használatba? 4. A DetailsPage.xaml (és ahogy később erről is bővebben szó lesz majd) OnNavigatedTo metódusa megpróbálja kinyerni a felhasználó által kiválasztott csempe indexét. És mivel egy adott csempe a kollekció egy részét reprezentálja, nekünk szükségünk van annak a csempének az indexére, amit az out kulcsszóval selectedItem kulcsként kinyerhetünk, és az pedig a VenueView.ID mezőjét jelenti (A queryString küldőt már a 4.1c pontban részletesen említettem) Tehát vele fogjuk azonosítani, és kikeresni a kollekció adott elemét a DetailsPage.xaml-ben, és részleteket megjeleníteni róla, továbbá vele fogjuk tudni megjeleníteni az 1.31b pontban tárgyalt Tips from a Venue API Endpoint hívást (A tippek lekérdezéséhez muszáj megadnunk egy Venue ID-t.) Az ObservableCollection típusról már tettem

említést az 1.32b pontban Megjegyezném, hogy ezek a kollekciók (ideális esetben) csak egyszer jönnek létre a program futása során (ezt a 2.c9-es alpontban az alkalmazás modellje résznél említettem meg). Most, hogy bemutattam, mekkora szerepet játszik mindhárom kollekció, a továbbiakban bemutatom a GPS és a DataQuery osztályok felépítését és működését, hogy később ismertethessem a MainViewModel osztály betöltő metódusait. 4.3 A DataQuery osztály Ennek az osztálynak a létrehozására azért került sor, hogy az API Endpoint-okhoz történő kapcsolódást, és a konkrét adatok letöltését és deszerializálását elválasszam az adatok kezelését végző MainViewModel osztálytól, mindazonáltal publikus, tehát más osztályok felhasználják tudását. Vegyük a következő adattagokat: 23 A konvenciónak megfelelően a privát tagok neveit aláhúzás jellel vezettem be. Láthatjuk, hogy az API kulcsokat konstansként definiáltam.

Kommentben láthatjuk a jelzést, hogy ez az osztály harmadik felektől származó könyvtárakat használ, hogy távoli szerverekhez kapcsolódhasson és a lekért adatokat a már meglévő modelljeimbe betölthesse, szintén leírtam a külső könyvtárak projektbe történő integrálásához szükséges konzolparancsokat. (Ezeket a Visual Studio NuGet Package Manager konzolba kellett beírni.) Az osztály két nagyobb tagfüggvényt, és két segédfüggvényt tartalmaz: Kezdjük a DataQueryForVenueViewModel(.) függvénnyel Az ábrán látható, hogy három paramétert vár: földrajzi szélességet, hosszúságot, és egy keresési kulcsszót - ez utóbbi alapértelmezett paraméterként (null) van megadva, ugyanis, ha a felhasználó nem vinne be értéket, futásidőben kivételt dobna a program. A függvény visszatérési értéke VenueModel típusú, és mivel távoli szerverhez kapcsolódunk, aszinkron kulcsszóval kellett bevezetnem. Folytatva a TipsFromVenueData(.)

függvénnyel, észrevehetjük, hogy csak egy venue ID-t vár paraméteréül (a helyszín azonosítóját), és mivel ő is távoli szerverhez fog kapcsolódni, olyan aszinkron típusú metódusról beszélünk, ami TipModel típust ad vissza. Az utolsó két segédfüggvény (azért segéd, mert az előbb tárgyalt két függvény törzséből hívom meg őket) két célt is szolgál: egyrészt logikusabbá teszi a kód elrendezését, másrészt javítja annak olvashatóságát. Vizsgáljuk meg őket egyszerre: szembetűnik, hogy alkalmaztam a függvénytúlterhelés gyakorlatát, de nem véletlenül: mind két segédfüggvény az adott típusú lekérdezéshez szükséges requestURL előállítására specializálódott, és kényelmessé teszi azok használatát. a. A DataQueryForVenueViewModel metódus Először nézzük a createRequestURL segédfüggvényt: 24 Az eljárás magáért beszél, nem sok magyarázatot igényel: megkapjuk a requestURL előállításához

szükséges bemeneti paramétereket, behelyettesítjük az URL-t prezentáló karakterlánc megfelelő záradékaiba, és a protokollnak megfelelően formázom, majd visszatérési értékként átadom a függvényt meghívó DataQueryForVenueViewModel metódusnak: Ami rögtön az előbb ismertetett visszatérési értékkel operál, létrehoz egy példányt a HttpClient osztályból (a System.NetHttp névtérben találjuk) Erre a példányra meghívom a GetStringAsync tagfüggvényt, paramé teréül pedig az imént előállított requestURL-t adom, a kérés (Http GET típusról beszélünk) eredményét pedig egy string típusba töltöm, majd az állapotváltozóval jelzem a kód további részében, hogy a lekérdezés sikeres volt. De miért fogalmaztam meg mindezt try-catch szerkezetben? Nos, előfordulhat, hogy kívüleső okok miatt megszakad az internetkapcsolat. Ilyenkor jön képbe a kivételkezelő, ugyanis, ha a GetStringAsync nem jár sikerrel, akkor

HttpRequestException típusú kivételt dob. Tehát tudatjuk a felhasználóval a probléma okát A folytatásban, létrehoztam egy VenueModel példányt (lásd az UML diagrammot a 3. fejezetből) Majd a JsonConvert DeserializeObject (Newtonsoft.Json névtér) tagfüggvényével szétsorosítottam (deszerializáltam), VenueModel típusúvá kasztoltam, és tartalmát átadtam a VenueModel példányomnak. Ez lesz a metódus visszatérési értéke is 25 b. A TipsFromVenueData metódus Az a. pontban leírt createRequestURL segédfüggvény nagyban hasonlít a Tips from a Venue verz iójának megfelelőjére, ugyanakkor magának a metódusnak a törzse is, így az a. pontban leírtak itt is érvényesek A különbséget a visszatérési típusban (TipModel) keressük, továbbá ennek a metódusnak a segédfüggvénye egy Venue ID paramétert vár a lekérdezés megfelelő működtetéséhez. 4.4 A GPS osztály Ezúttal a projekt legkisebb osztályát mutatom be. Mindössze egy

metódust, és egy segédfüggvényt tartalmaz Megtehettem volna, hogy egy nagyobb osztály részévé teszem, hogy később annak példánya által hozzáférjek, de éppen ez az objektum orientált programozás lényege: a fogalmakat tisztán érthetővé tesszük, modulárisan ábrázoljuk, és meghatározuk a modulok közötti kapcsolatokat.Így sokkal érthetőbbé válik a forráskód annak aki majd elolvassa a. Az UpdateMyMap metódus Vegyük a következő kódot: Létrehoztam egy Geolocator (Windows.DevicesGeolocation névtérből származik) és egy DataQuery (lásd: 43 pont) típusú osztálypéldányt. A Geolocator példány DesiredAccuracyInMeters (kívánt pontosság, keresési körzet) tulajdonságának explicit típuskényszerítéssel átadtam a DataQuery egy publikus adattagját. A kasztolásra azért volt szükség, mert a DesiredAccuracyInMeters-nek előjel nélküli egészre (unsigned integer) van szüksége. A következőkben példányosítottam egy

ProgressIndicator-t, hogy az alkalmazás felhasználójával tudathassam, hogy a telefon éppen a GPS pozíciók meghatározását végzi. Segédfüggvényként a SetProgressIndicator -t használtam fel, ami annyit tesz, hogy amint a készülék meghatározta saját helyzetét, a ProgressIndicator Visibility tulajdonságát egy boolean false értékkel kikapcsolja (isVisible). Tovább tekintve a kódot, elég alacsony szintű (ám annál optimálisabb megoldásként) létrehoztam egy double típusú, 2 elemű tömböt. Mivel nekünk nem kell az egész Geoposition objektum, csak annak Coordinate tulajdonságpárja (szélesség & hosszúság), ez lesz a metódus visszatérési értéke is. Megjegyzés a try-catch szerkezettel kapcsolatban: Egy mobilalkalmazás számos hardveres funkciót közvetlenül felhasználhat (pl. VOIP, Micophone, Camera, Gamer Services stb). Mindazonáltal ezekhez a funkciókhoz történő hozzáférési kérelmeket mind engedélyezni kell fejlesztői oldalon

is (WMAppManifest.xml fájlban), és felhasználói oldalon is (a fizikai k észülék beállításainál). Lássunk egy ábrát: 26 A Capability attríbútumok óriási szerepet játszanak az alkalmazás működésében. Alapértelmezés szerint az "ID CAP LOCATION" és az "ID CAP MAP" tulajdonságok (képességek) nincsennek engedélyezve. Ezt nekünk, fejlesztőknek kell megtenni, mint ahogy a hardverigények, és hardverfunkciók hozzáféréseinek behatárolásait, és megfontolásait is. Visszatérve a try-catch szerkezetre: tudatjuk a felhasználóval, hogy addig nem tudja teljes körűen használni az alkalmazást, ameddig be nem kapcsolja a helymegosztást a készülék beállításaiban (location). 4.5 A MainViewModel betöltői Az eddigiekben ismertettem a MainViewModel osztály szerepét, kollekcióit, kitértem azokra az osztályokra amiket felhasznál, illetve mindezek tulajdonságaira. A következőkben bemutatom azokat a betöltőket, amik a

feldolgozott adatok megfelelő kollekciókhoz történő eljuttatásáért felelősek - lehetővé téve azoknak a felületen történő megjelenítést. a. A LoadVenues metódus Ennél a metódusnál részletesen leírom azokat a tulajdonságokat és eljárásokat, amik által megérthetjük a felület frissítési mechanizmusait, a hibák kikerülését és kollekciónk frissen tartását. Mivel mindhárom betöltőm működési elve nagyban hasonlít, így először részletesen kifejtem a LoadVenues működésének logikáját, hogy a többi betöltőnél csak azokra a kódrészletekre kelljen öszpontosítanunk, ahol más típussal - és/vagy más elv szerint működnek. Ezt a metódust négy ábrán keresztül fogom ismertetni, láss uk az elsőt: A metódus másik osztályból származó SZINTÉN aszinkron típusú függvényeket hív. Tehát ameddig a hívási hierarchia tetejére nem értünk, minden olyan metódust ami egy aszinkron függvényt hív meg, async kulcsszóval

kell jelölni. Ez az 27 egységességet hivatott feloldani. Vegyük a paramétert: kapunk egy string típust (keresési kulcsszó) ami null értéket is felvehet (lásd a hívó osztályt, ami a MainPage). Ezek után kritikus inicializációs problémákat oldottam fel: a későbbiekben a Venues kollekcióhoz minden LoadVenues híváskor VenueView példányokat adunk. Későbbiek alatt értsük a következőket: 1. A MainPage konstruktora meghívja a LoadVenues metódust (betöltődnek a találatok). 2. Elnavigálunk a DetailsPage-re, majd onnan vissza a MainPage-re, tehát a MainPage OnNavigatedTo metódusa újra meghívja a LoadVenues metódust, ami a már meglévő kollekcióhoz hozzáadja az "új" találatokat is! Így hibás, duplikált adatok fogják megütni a szemünket. Ennek kivédésére minden LoadVenues híváskor "kitakarítom" a Venues kollekciót, ami a felület frissítésének illúzióját fogja kelteni ezért hívom meg a Clear

függvényt minden betöltéskor. A kollekció példányokat tárol, a példányok pedig rekordokat. Rekordoknak tekinthetjük az ábrán látható üres string-ek sorozatát. Nevükhöz megfelelően, a megfelelő adatokat fogják megkapni Majd létrehoztam a VenueModel, DataQuery, GPS és a List<VenueData> példányokat, a továbbiakban ezekkel dolgoztam: Egy double[] tömbbe (néha kényelmesebb a var jelölés) betöltöttem a GPS példány UpdateMyMap tagfüggvénnyel lekért koordináta párost. A DataQuery példány DataQueryForVenueViewModel tagfüggvényével, és az előbbi GPS példány koordinátáinak segítségével lekérdezem a helyszín és keresőszó specifikus adatait, és átadom a VenueModel példányának. Nekünk nincs szükségünk az egész VenueModel-re, a továbbiakban elegendő lesz a VenueData példány is. Ezt látjuk a 92-es sorban. A try-catch megfontolások megfogalmazását lásd: 43a pontban Most pedig nézzük a rekordok előállítását

végző formázásokat és ciklusokat: A 96-os sorból induló for ciklus feltételeként a VenueData példányának elemszámát vesszük. 28 Ciklusváltozóként az item-et használom, ezzel fogom beazonosítani a soron következő elemet. Az item minden iterációban addig inkrementálódik eggyel, amíg az kisebb az elemek számánál. A folytatásban a metódus törzsének elején bevezetett string-eknek értékül adom az aktuális indexű példány megfelelő tagját. A 103, 115 és 120-as sorokban a mintának (kommentben látni) megfelelően történik a formázás (ezt kapjuk a kimenetre). Vegyük észre az egyes adattagokra meghívott ToString() függvényeket: mivel nem terveztünk számításokat végezni adatainkkal, hanem csak írni/olvasni, és a kimeneten megjeleníteni, ezért bőven elég string típusban tárolni a rekord elemeit. Ezért egyes adattagokat explicit módon string típussá alakítva adtam át a megfelelő változóknak. Alkalmazásom

kategóriákat is képes lesz megjeleníteni az adott helyről (DetailsPage), így ennek a karakterláncnak az előállítása egy beágyazott for ciklus keretén belül történik. A (külső) for ciklus törzsének végét a következő ábra szemlélteti: Mi történik pontosan? A this kulcsszó az osztályon belül keresi meg a hivatkozott elemet, és azzal csinál valamit. Jelen esetben, kiválasztja a Venues kollekciót, meghívja rá az Add (elemek hozzáadása) metódust, és új VenueView példányt hoz létre, aminek HELYBEN értékül adja az imént előállított karakterláncainkkat (tulajdonképpen egy rekordot). Ennek fényében kijelenthető, hogy a ciklus futása során minden iterációban ho zzáad egy rekordot, azaz leképez egy táblát. Megjegyzésként, az IsDataLoaded állapotjelző tulajdonság jelzi a futtatómotornak, hogy az aktuális nézetet egy munkameneten be kell-e betöltenie. Lásd: MainPage OnNavigatedTo eseménye Immáron teljes mértékben

ismertettem a MainPage működését. A továbbiakban áttérünk a DetailsPage oldalra, és bemutatom annak felépítését is. 5. Funkciók, algoritmusok és forráskódok 2 rész Miután a felhasználó "találkozott" a főoldallal, egy csempére történő tapintással átnavigálhat a részleteket összesítő oldalra. A MainPage osztály navigációs metódusát lsd: 2f pontban 5.1 DetailsPagexaml a. A "TipLongListSelector" A 4.1c pontban kitértem a LongListSelector működési elvére, adatkötési módszereire és vizuális erőforrás-definícióinak elérési módszerére, így a soron következő oldalakat és komponenseiket rövidebben össze tudom foglalni, és csak azokra a pontokra térek ki, ahol a XAML kód magyarázatot igényel:  A vezérlő ezúttal List típusú vizuális elrendezést k apott, hogy a kapott tippek kényelmesen olvashatóak legyenek. A mögöttes kódból "TipLongListSelector" néven hivatkozok a komponensre

(erről később) 29  A LongListSelector statikus erőforrása ugyanabban a DetailsPage.xaml dokumentumban van, és "DetailsPageList"-ként hivatkozok rá - innen jön a vizuális struktúra.  A vezérlő adatkötést valósít meg a Tips kollekcióval - ennek gyermekelemei jelennek majd meg rajta.  A "DetailsPageList" erőforrásban lévő StackPanel (verem) gyermekelemei 3 TextBlock vezérlőt prezentálnak. Ezek konkrét attríbútumokhoz valósítanak meg adatkötést.  A XAML kódhoz tartozó adatok tervezési időben történő megjelenítéséért a DetailsPage SampleData.xaml statikus forrás felel (Design Time Data)  A vezérlő futási időben a TipModel-ből veszi az adatokat, a MainViewModel osztály LoadTips metódusa segítségével (erről is később). b. A "DetailsPageTitle" adatforrása Ebben az esetben az oldal címét úgy kellett bevezetnem, hogy annak értéke a navigációt kezdeményező csempéről

származó adatok Name (a helyszínt adja) tulajdonságából származzon. Az alábbi kódrészlet azt mutatja, hogy a TextBlock Text attríbútumának adatkötéssel a Name property-t adtuk: A 62-es sorban adatkötés valósul meg. De honnan tudja a futtatókörnyezet, hogy mi most melyik Name-re gondoltunk? Idézzük vissza a LongListSelector ItemsSource attríbútumát! Pl.: konkrétan meg volt nevezve, hogy a Binding-ot a Venues kollekcióra szeretnénk érteni. Akkor itt most mi a helyzet? Az ábrán futásidőben prezentálandó, kiválasztottam egy elemet a főoldalról (ilyenkor beindul a MainPage MainLongListSelector SelectionChanged eseménye): A DetailsPage.xaml oldal mögöttes kódjában (cs) elhelyeztem egy töréspontot, és debug üzemmódban nyilvánvalóvá válik, hogy az oldal DataContext-jét a kiválasztott elem indexe alapján határozza meg (amit egy QueryString-ként kap meg az oldal, és annak kulcsát keresi ki). Tehát: a kinyert index alapján a

futtatómotor kikeresi a Venues kollekció kívánt elemét, és magává az oldal DataContext-jévé teszi! Így oldódik fel az oldalak közötti adatcsere problémája, és így vállnak ábrázolhatóvá a továbbiakban azok az adatok, amiket részletesebben fel szeretnénk tüntetni az oldalon. (A TipModel-ből és a VenueModel-ből származó adatokra gondolok) Most, hogy már bemutattam, hogy hogyan valósul meg a felületi elemre történő adat kivezetése ItemsSource deklaráció hiányában (62 es sor), áttérhetünk a következő komponensekre. c. További TextBlock-ok Az oldal fennmaradó (középső) sávjában (ami egyébként egy Grid-en kapott elhelyezést) a következőket helyeztem el: 30   Image vezérlő: egy statikus képet ad (design elem), Három különálló TextBlock vezérlő: mindegyik egy adott kollekcióhoz valósít meg adatkötést. Vegyük észre, hogy mind a VenueModel-ből, mind a TipModel-ből vesznek adatokat (Location, Stats,

Categories. Lsd: UML ábra a 3. fejezetben) Az adatkötés további kérdéseit pedig a 41c pontban tárgyaltam. d. Megjegyzés a DetailsPagexamlcs osztályával kapcsolatban Az oldal C# kódjában lévő DetailsPage osztály parciális, és PhoneApplicationPage interfészt valósít meg. Deklaráltam két privát elérésű string-et, külön kommentben feltüntetve, azok létjogosultságát: Ennek a két változónak a szerepét majd a harmadik oldal (UserFavourites.xamlcs) bemutatásánál fogom ismertetni. Addig gondoljunk rájuk úgy, hogy segítségükkel működhetnek a kedvencek hozzáadását, és törlését megvalósító eljárások. Az 5.1b pontban részletesen leírtam, hogy származnak a különböző TextBoxokhoz tartozó adatok (NavigationService -> SelectionChangedEventArgs -> indexlekérés -> VenueModel -> Venues kollekció[index] eleme -> DataContext beállítás.) Viszont még nem tértünk ki a LongListSelector ItemsSource tulajdonságra

részletesen. A választ az oldal alapértelmezés szerinti OnNavigatedTo eseménykezelője adja, amit maga a Windows Phone Runtime Engine indít el. Már volt róla szó az 51b pontban, de most nézzük meg azt a kódrészletet, ami a konkrét betöltésének kezdeményezéséért felel, konkrétan a 32-es sortól! (Még mindig az osztály OnNavigatedTo metódusán belül vagyunk.) Látható, hogy a 33-as sorban elindítjuk a MainViewModel osztálypéldányának LoadTips metódusát, és mi nagyon fontos: átadjuk neki a Venue ID-t, hogy a későbbi mechanizmusok megfelelően szállíthassák az adatokat. A LoadTips metódus nagyon hasonló a LoadVenues metódushoz, illetve azokat az osztályokat használja, amikről korábban már volt szó - konkrétan a DataQuery osztályt, és azok megfelelő tagfüggvényeit. Majd, miután az adattagok megfelelő formázását követően készen va nnak a TipView példányok, és maga a konkrét kollekció is, a DetailsPage osztály

OnNavigatedTo metódusának 34-es sorában értékül adjuk azt a "TipLongListSelector" (LongListSelector) ItemsSource tulajdonságának. Tehát - mint ahogy azt sikerült bemutatnom - az objektumok tulajdonságai XAML-ben és C# kódban kombináltan módosíthatóak. Ebben az esetben azért volt szükség a C# kódból történő tulajdonságmódosításra, mert a programnak meg kellett várnia a SelectionChanged eseményt (a felhasználó választását), hogy elkezdhessen dolgozni az adott elemmel. Ha visszatekintünk az előző ábra 36-os és 37-es sorára, az alfejezet első bekezdésében említés került az ott látható két globális string változó bevezetésének okára (kedvencek funkció).Tulajdonképpen elmentem a Venue ID-t, és a Name-t, amivel később megvalósíthatóvá tettem a kedvencek funkció implementálását. 31 e. A "saveBarButton" funkciója Miután sikerrel megjelenítettünk minden adatot az adott helyszínről (a hely nevét,

tőlünk lévő távolságot, tippeket stb.), szeretnénk lehetőséget adni a felhasználónak arra, hogy egy elmentse a helyszín nevét Erre a célra szolgál a BuildLocalizedApplicationBar() metódus, ami projektsablon szinten benne van a forráskódban, csak nekünk fejlesztőknek kell rajta alakítani. Ebben az esetben, átneveztem a saveBarButton példányt (a következetesség érdekében), és hozzárendeltem az Assets projektmappában található save.png -t Miután hozzáadtam az ApplicationBarhoz, és elérhetővé tettem, hozzárendeltem egy Click eseménykezelőt Ezt az eseménykezelőt látjuk kifejtve az alábbi ábrán: A 70-es sor egy előformázott QueryString-et reprezentál, ami beépíti azokat a globális string-eket, amelyek a kedvencek funkció működtetéséhez szükséges adatokat tartalmazzák(Venue ID, Name). Majd a 71-es sorban hívott NavigationService osztály Navigate metódusának átadom paraméterként (URI), és megtörténik az

UserFavourites.xaml-re történő navigáció A továbbiakban ezt az oldalt fogom ismertetni. 5.2 UserFavouritesxaml A DetailsPage után szabadon - bemutatom az alkalmazás utolsó oldalát, az UserFavourites -t: Ezen az oldalon a felhasználó egy listát menedzselhet, ami tulajdonképpen a "Kedvencek" funkciót hivatott prezentálni, először vegyük az oldal tartalmát. a. A "FavList" szerepe Ez a vezérlő SZINTE teljesen megegyezik a LongListSelector vezérlő működési elvével, azonban számos különbség is szembetűnik:  A vezérlőre a toolkit: névtérből hivatkozok amit a Coding4Fun könyvtár projektbe történő installációval tettem elérhetővé (NuGet).  Funkcionális különbségeit tekintve kijelölhető CheckBox-okra emlékeztető területeket kapunk a képernyő (illetve minden egyes lista elemének) bal oldalán, mely CheckBox-okból több is kijelölhető egyszerre.  A XAML kód sémákat és névtereket definiáló

részébe be kellett építeni a Coding4Fun Toolkit.Controls komponensre való hivatkozást. A lista egy eleme a helyszín nevét jeleníti meg. Ha a felhasználó kijelöl egy elemet, az oldal alján egy törlés gombot prezentáló gomb jelenik meg, felkínálva ezzel a törlés lehetőségét. Mielőtt továbbmennénk, nézzük meg gyorsan az oldal XAML layout-ját:  Az oldal LongListMultiSelector vezérlője DESIGN időben a projekt SampleData mappájában lévő UserFavourites SampleData.xaml-ből nyeri ki az adatokat 32  Futási időben a lista ItemsSource attríbútuma a MainViewModel Favourites kollekciójából töltődik fel adatokkal. Itt is meghatároztam egy statikus erőforrást, amire a "FavouritesPageList" kulcs által tudok hivatkozni az ItemTemplate-ből.  Egy listaelemet megvizsgálva, kiderül, hogy egyetlen Grid-be ágyazott TextBlock vezérlőről van szó, ami adatkötést valósít meg a Favourites kollekció UserFavVenue

property-jével. Most pedig térjünk át az oldal mögöttes kódjára! b. Az UserFavouritesxamlcs, a DetailsPagexamlcs és a MainPagexamlcs kapcsolata A DetailsPage osztályban lévő saveBarButton Click esemény aktiválódásakor egy NavigationService metódust hívtam meg, így a helyszín mentéséhez az userFavID, és az userFavVenue változók értékeire lesz szükség. Így ezeket adtam át egy URI példányaként az UserFavourites.xamlcs OnNavigatedTo eseményében Először nézzük a try blokkot a 39 -es sortól: Mivel a MainPage osztály BuildLocalizedApplicationBar metódusát kiegészítettem egy újabb ApplicationBarIconButton példánnyal (appBarFavourites névvel), ezért, annak appBarFavourites Click eseménykezelője is az UserFavourites.xaml-re navigál át, mégpedig QueryString paraméterek nélkül! Ezt a problémát hivatott feloldani a try azzal, hogy a kulcs lekérésének sikertelensége esetén a catch blokk elkapja a KeyNotFoundException típusú

kivételt, így az alábbiak szerint intézhettem a vezérlést: A favourites egy Dictionary<string,string> kulcs-értékpár tároló, tehát egy ugyanilyen visszatérési értékkel operáló ReLoadFavourites metódust vezettem be. Majd ezen metódust használtam arra, hogy a telefon izolált tárterületéről visszaolvassam azt a fájlt, amit a elhasználó az előző munkamenetben ott hagyott (ezt az eljárást részletesen ismertetni fogom később). Mindenek előtt, koncentráljunk az if blokkra Meghívom rá a Count metódust, és ha nincsennek elmentett kedvencei, akkor tudatom vele ezt az információt, mitöbb, megakadályozom, hogy egy üres képernyőt kelljen bámulnia. Ezért hívtam meg a NavigationServiceNavigate metódusát is, ami a MainPagexaml-re irányít vissza, és kitör a blokkból (return). De mit csinál az else blokk? Korábban már ismertettem a MainViewModel osztály betöltőit, most viszont kicsit más a felépítése. Azonban, hogy teljes

legyen a kép, ismerjük meg az UserFavourites osztály adattag jait: 33 FONTOS, hogy az imént tárgyalt OnNavigatedTo metódust még nem ismertettem teljesen! A továbbiak megértéséhez azonban fontos, hogy lássuk a fenti ábrán lévő tárolókat. Deklaráltam két teljesen egyező nevű segéd string-et (24-es és 25-ös sor), a kedvencek törlése / létrehozása idején szükséges azonosíthatóság érdekében. Látható, hogy egy konstans string-et (30-as sor) is létrehoztam: ezzel a karakterlánccal nevezem meg azt a fájlt amit a fájlkezeléssel kapcsolatos metódusoknál törlésre / létrehozásra használhatok. Vegyük észre a JSON kiterjesztést Mentésnél sorosítanunk kell (szerializáljuk az adatokat). Vegyük a 32-es sor kulcs-értékpár tárolóját: minden fájlból való kiolvasás, abba történő beszúrás, vagy törlés esetén az operatív memóriából töltjük fel / le az adatokat. Tulajdonképpen más fontos szerepet is betölt: Teljesen

nyilvánvalóvá válik, hogy el szeretnénk kerülni a duplikációkat és az adatsérüléseket. Ezért, minden egyes kulcs a helyszínt prezentáló egyedi azonosítót kapja értékéül. De miért statikus a tároló? Mivel az oldalak közötti navigálás hatására a vezérlés oldalak, ezen belül különálló osztályok és metódusok között megy végbe, az automatikus változók addig "élnek", amíg a vezérlés ki nem kerül annak hatóköréből. Ezt hivatott feloldani a static kulcsszó, amivel "emlékezetet" biztosíthatunk változóinknak. Mielőtt folytatnánk az OnNavigatedTo törzsének további részeivel, be kell mutatnom az osztály fájlkezeléséért felelős metódusait. 34 c. ReSaveFavourites és IsolatedStorage Ennek a metódusnak a szerepe, az adatok elmentésében merül ki. Két paramétert vár: a menteni kívánt file nevét, és az adatokat tartalmazó kulcs-értékpár tárolót: A 140-es sorban egy JSON string-be

szerializálom a szótár tartalmát. Ez az adat fog a telefon izolált tárterületére kerülni Mivel a Windows Phone operációsrendszerbe integrálódó appok saját Isolated Storage -et kapnak, CSAK ebben a tárterületben végezhetünk műveleteket. Ez biztonsági okokból van így Mivel több alkalmazás létezik a rendszeren belül, saját adatállománnyal, meg kell őket óvni attól, hogy egy rosszindulatú kód felborítsa azok működését, esetleg adatokat szivárogtasson ki róluk (pld.: banki applikációk), hogy aztán eljuttassa azt egy távoli szerverre Ezért, hogy ezekkel az adatokkal a továbbiakban dolgozni tudjak, le kellett kérdeznem a saját alkalmazásom IsolatedStorage elérési útvonalát a GetUserStoreForApplication tagfüggvénnyel. De mik azok a using záradékok? Tuladonképpen unmanaged resources-szal dolgozunk, és egy ilyen speciális jelöléssel kell ellátni, jelezvén a fordítónak, egy IDisposable kezelt interfészről van szó . Így I/O

interfészekhez férünk hozzá, buffereket (FileStream, AudioStream stb.) kezelhetünk, mindezt úgy, hogy a szemétgyűjtő (GC - Garbage Collector), azaz a managed környezet mit sem tud róla. Tehát amint kiérünk a using blokkokon kívülre, végrehajtódik az IDisposable, és az addig lefoglalt erőforrások felszabadulnak. Ennek tudatában, a 144-es sorban a lekérdezett izolált tárterület elérési útvonalának gyökérmappájában létrehozom a paraméterül kapott névvel a fájlt, és a belső using záradékban indítok egy StreamWriter objektumpéldányt, amire meghívom a Write metódust, és kiírom a fájl tartalmát. d. ReLoadFavourites Az előző c. pontban tárgyalt metódushoz nagyon hasonló működésről tanúskodik: felhasználja az unmanaged erőforrásokat, a paramétereként kapott string alapján pedig megnyitja, majd teljes egészében beolvassa a fájlt, és egy szótárba deszerializálja azt a JSON adatot, amit előtte mentettünk el. Ez a szótár

lesz a függvény visszatérési értéke is, és ezt a szótárat adjuk át az osztály statikus szótárának mint értéket, hogy ha az oldalak közötti navigáció végbemegy, az adatok rendelkezésre álljanak. Ugyanis, a soron következő MainViewModel LoadFavourites metódusa ezt a szótárat fogja felhasználni a kollekció példányainak létrehozásához, és kimeneten történő megjelenítéséhez. e. LoadFavourites A MainViewModel osztály tagfüggvényének átadott szótár Favourites kollekcióhoz példányokat betöltő metódusa hasonlóan működik a felette lévő kettőhöz, viszont más technikát alkalmaztam az iteráció megvalósításához: 35 Az ábrán látható foreach ciklus KeyValuePair típusban ábrázolja a Dictionary minden elemét. Ezzel lehetőségem nyílt Key és Value szerint hozzáférni az adatokhoz, majd azokat értékül adni a megfelelő property-knek, minden egyes iterációkor. A 172-es sorban lévő kód a felület frissítéséért

felel, mint ahogy azt a 4.5a pontban leírtam f. Az OnNavigatedTo (folytatás) Miután a c., d valamint e pontokban kitértem azokra a metódusokra amelyeket a b pontban vizsgált OnNavigatedTo eseménykezelő használ fel, rátérhetünk a blokk további részére: Mi történt eddig a kódban? Amennyiben a felhasználó a DetailsPage-ről navigált ide, volt használható kulcsunk, és nem lépett ki a vezérlés az előző try blokk feltételében (break). Az ábrán egy újabb try-catch szerkezetet vehetünk szemügyre A 64-es sorban - ahogy kommentben meg is jegyeztem - defenzív módon megakadályoztam annak lehetőségét, hogy több azonos rekordot vigyek be a kollekcióba. A 67-es sorban a 66-os sor által frissített kollekció után a MainViewModel osztály kollekciója is frissül. (Emlékeztetem az olvasót a Dictionary statikus voltára!) Ezután, elmentjük a frissített kollekciót, és a vezérlő kilép a szerkezetből. A catch blokk gyakorlatilag semmilyen

adatmozgatást nem végez, mivel az adott elem már szerepel a kollekcióban. Végül: a 78-as sorban explicit módon hozzárendelem a LongListMultiSelector (FavList-nek neveztem el) vezérlő ItemsSource tulajdonságának a frissített kollekciót. Ezzel készen is volnánk, a soron következő pontokban kifejtem a törlés funkció működését. g. Kedvencek törlése Az 5.2a pontban leírt funkcionális működést tekintve több elem kijelölhetőségével számolhatunk Amennyiben a felhasználó több elemet kijelöl, a futtatómotor megszólítja a LongListMultiSelector SelectionChanged attríbútumának 36 eseménykezelőjét, és az alábbi hajtódik végre: Az oldal alján elhelyezett ApplicationBar megjelenik - már ha van kijelölt elem, ezen felül, rajta találunk egy Törlés gombot, mely a kijelölt elemek törlés elindítását végző Click eseménykezelőt szólítja meg: Nézzük a 101-es sort: a foreach ciklus azt mondja meg, hogy csak a lista kijelölt

elemeit vegyük. Ez azonban System.Object típusú, így tudatnom kellett a fordítóval, hogy valójában FavouriteView típusra gondolok! Ezzel feloldottam a következőket:  A 103-as sorban meghívom a Dictionary típus Remove tagfüggvényét, és az iteráció során azokat az elemeket távolíttatom el, amelyek a kijelölésben szerepelnek.  Minden ciklusfordulóban meghívom a ReSaveFavourites metódust lásd.: 52c pont Végül, a 113-as sorban frissítettem a MainViewModel Favourites kollekcióját. 6. Az alkalmazás tesztelése Most, hogy nem csak bemutattam, hanem ismertettem is alkalmazásom forráskódjának összes lényeges részét, elérkeztünk magához a teszteléshez. A fordítót Debug üzemmódról Release -re állítottam, így egy XAP fájlt állít össze a Visual Studio. Ezt a XAP fájlt kell átadni a Microsoft DevCenter Submit App portálján, de csakis akkor, ha a Visual Studio Store Test Kit összes tesztjén megfelelő teljesítményt nyújt,

hibamentes, és a Platform á ltal támogatott felbontások emulátorban történő kipróbálása esetén is gond nélkül lefutott. 37 6.1 Automatikus tesztek A publikálásra szánt alkalmazásnak első körben három követelménynek kell megfelelnie:    Hiánytalan XAP fájl (ami az assemblyn-ken kívül tartalmazza az asset-eket, és a manifeszt fájlt is). Mind három képernyőfelbontásról legalább egy képernyőképet kell készíteni. Az összes (small, medium stb.) csempe-ikonoknak rendelkezésre kell állniuk Miután biztosítottam a fentieket az automatikus teszt sikerrel lefutott: 6.2 Teljesítménytesztek A teljesítménytesztek lényege az alkalmazás futtatásakor monitorizált és diagnosztizált problémák felderítése. Elsősorban a minőségbiztosítás és a különböző hibák felderítése a cél. Az alkalmazás emulátorban való tesztelése nem éppen szerencsés választás. Éppenséggel azért, mert egy különálló virtuális

gépként él az operációs rendszerben, és nem használ grafikus gyorsítóchip-et. Történetesen magát a fizikai készüléket, és annak kondícióit hivatott szimulálni Lássunk egy teljesítménytesztet: fizikai tesztkészüléknek a saját Nokia Lumia 620-asomat használtam. A Windows Phone Application Analysis tesztet kb. 1 percig futtattam, ez alatt az idő alatt pedig az oldalak közt oda -vissza nagyon gyorsan 38 navigáltam adatokat folyamatosan frissítettem (kereséssel, navigációval, mentéssel). Lássuk az eredményeket: Az analízis létrehozott egy ProjektNév Dátum.sap kiterjesztésű fájlt a projekten belül Az összefoglalón látszik, hogy 6 figyelmeztetést adott a Visual Studio, az alkalmazás indulási ideje megüti a mércét, a válaszidő pedig gyenge (ezeket mindjárt kiderítem, hogy miért gondolta így). A táblázat további részeit figyelve látható, hogy alkalmazásom 54 másodperces futásideje alatt 4.49 mAh-t fogyasztott, ami az

EGÉSZ telefont képes lemeríteni 506 óra alatt (ehhez 5 órán keresztül kellene eszeveszett tempóval használni az app funkcióit). Sajnos ez nem véletlen, de nem is szerencsés eset Miután átnéztük, hogy emögött a "párfunkciós" app mögött is mekkora adatok mozognak (az más kérdés, hogy mit látunk belőlük), és, hogy tartalmaz néhány erőforrás -igényes algoritmust, és aszinkron műveletet. Nos, valós, piaci szempontból nézve számos helyen refaktorálásért kiáltana a forráskód. Mennyi operatív memóriát fogyasztott az alkalmazás? A táblázatból leolvasható, hogy 41.49 Mbyte -ot Ez a méret 60 szorosa az alkalmazás XAP fájljának. (Érdekesség képpen) A letöltési ráta majd kerek egy perc alatt 020 Mbyte -ot jelentett. Ha 10 percig ugyanilyen tempóban használtam volna az appot, 2 Mbyte-ot vitt volna el Térjünk át arra a grafikonra, amit az Analysis generált nekünk: 39 Amit itt kaptunk, az egy részletes kimutatás az

alkalmazás futásideje alatt monitorozott mérésekről. Ezek a mérések a CPU százalékos kihasználtságát, a leképezett (renderelt) képkocka/másodperc mértékét, és a külső események behatásait tartalmazzák (pl.: tapintás, interakció stb) Az idősávot 05 másodperces lépésközre állítottam, és kiragadtam a grafikon egy olyan darabját, ahol költséges számításokra figyelmeztet a Performance Warnings tábla azon sora, ahol a jelzés ténye mellett, fel van tüntetve az időintervallum, és az erre tett javaslat. Lássuk pontokba szedve: A grafikon idősávján haladva - és a frekventált részeket felnagyítva elkezdhetjük vizsgálni az adott intervallum CPU fogyasztását, és az eszközölt interakciókat. Megfigyelve az U-val (User Interaction) jelölt flag-ek egyikét, az IDE kimutatja annak eredetét is, esetünkben, a 26 másodpercnél a keresést indítottam, ezzel a futtatómotor felfüggesztette a renderelést (ez látszik a 26 - 27 másodpercek

között, amíg a keresődobozba beírtam a kifejezést). Ezek a flag -ek akkor bizonyulnak hasznosnak, ha egy nagyon összetett, és erőforrásigényes funkció szekvenciáit szeretnénk alaposan megfigyelni. Szerencsére figyelmeztetéseket is kapunk, például, azokat a menedzselt szálakat is "elkaphatjuk", mely(ek) gyakorlatilag 57.62 %-os CPU kihasználással üzemel(nek) Ezzel feloldódik az optimalizálás kérdése Én ez esetben nem hajtottam végre refaktorálást, más esetben viszont fontolóra vettem volna. 40 6.3 Mennyi CPU erőforrást fogyasztanak a saját függvényeim? Lássuk az alábbi kimutatást (még mindig az Analysis riportját vizsgáljuk): Megfigyelhetjük, hogy immáron DLL-ből (emlékezzünk vissza, hogy Release módban fordítottam le a projektet!) vesszük egyes metódusok Stack Trace %-os értékét. Ezek a számok jól jelzik az vizsgált metódus hatékonyságát, és jól behatárolják azokat a fogalmakat amikkel jelentős

optimalizálásokat is végrehajthatunk. 6.4 Manuális tesztek Itt nem térnék ki különösebben a manuális tesztek részleteire: lényegében egy olyan minőségbiztosítási mechanizmust jelent, amely kiszűrheti azokat az alkalmazásokat, amelyek hibásak, és/vagy nem kezelt, fel nem fedett bugokat tartalmaz(hat)nak. Nem minden manuális teszt eset alkalmazható egy app -ra Vannak fotó-specifikus, kamera-specifikus stb. tesztek Összefoglalva, a tesztek segítenek minket fejlesztőket, hogy egy olyan produktumot dobhassunk piacra, amelyek, pozitív felhasználói/vásárlói viszhangot keltenek. Fontos, hogy a tesztek óriási szerepet játszanak a szoftverfejlesztésben, így mindig összhangba kell hozni azokat a fejlesztési mérföldkövekkel. 7. Publikáció és utószó: hogyan tovább? Ebben a fejezetben röviden leírom, hogy a mai piaci körülmények tekintetében, milyen módon lehetséges egy szoftver áruházban saját alkalmazást értékesíteni, vagy ingyen

felhasználhatóvá tenni. 7.1 Microsoft Dev Center Alkalmazásom, Store-ba történő publikációjához regisztrált fejlesztői fiókkal kell rendelkeznem (ami 99 USD-t jelent). Miután kifogástalanul működik az alkalmazás, a Dev Center portálján keresztül történhet meg a XAP fájl feltöltése, lokalizációs beállításai (milyen országokat, piacokat akarunk megcélozni), és az alkalmazás jellemzésének kitöltése. Ez utóbbit egyébként a Visual Studio-ból is megtehetjük: 41 Miután alkalmazásom felületi részeit (főként a dolgozat céljából) magyar nyelven jelenítem meg, csak magyarországi piacot tehetek támogatottá. Ezt a palettát viszont (ha akartam volna) tovább bővíthettem volna például új resx fájlok létrehozásával a projektben. Ezt most nem tettem meg, mert nem kapcsolódnak szorosan a fejlesztés kérdéséhez Utómunka részeként viszont tökéletes elfoglaltság a honosítás. Az alkalmazás verzióját, kiadója, kiadó

neve szintén megjelenik az áruházban. Ezt is leellenőrizhetjük a Visual Studio segítségével: A Product ID-re gondolhatunk úgy, mint egy autó alváz számára. Egyedi a zonosítót prezentál Miután elküldöm a XAP fájlt a Microsoft szervereire, számos tesztelési fázist követően - ami a közleményben 5 munkanapig tarthat - és validációt követően (amennyiben megfelelt a produktum), megjelenik az áruházban. Ezáltal valódi embereknek is elérhetővé válik az app, és várhatom a pozitív & negatív visszajelzéseket (crash report, bug report, Q & A stb.), fejlesztési javaslatokat Elérkeztünk hát az összefoglalóhoz 7.2 Összefoglaló Számos IT (information technology) óriás közül választhatunk: Apple, Google, Microsoft stb. Mind-mind rendelkeznek már azzal a sajátos, kifinomított platformmal, amelyre (vagy akár mindre) fejleszthetünk appokat. Független (köznyelvre fordítva: szabadúszó) fejlsztőként, saját hobby project-et

publikálhatunk a 6. fejezetben ismertetett tesztelési fázist ÉS a platform filozófiáját követve (Design Guide). Szakdolgozatom szóban forgó applikációját (megjegyzem: életem első Windows Phone 8-ra fejlesztett alkalmazását) megfontolom, hogy jelen állapotában publikáljam-e a Microsoft Dev Center-en keresztül a Store-ba. Mint hangsúlyoztam: egy párfunkciós appról van szó Mindazonáltal, a teszteknek megfelel, és az alsókategóriában is megtalálja a helyét. Lehet, hogy kiegészítem még további funkciókkal, de az is lehet, hogy újabb projektek fejlesztését fogom kivitelezni, illetőleg számos API megismerését, hogy 42 még gazdagabb élményt nyújtó szolgáltatásokkal operáló appokat tudjak kifejleszteni, közzé tenni, vagy egy ilyen projekten dolgozó csapat tagját képezni. Szándékaim szerint a jövőben továbbra is fejleszteni fogom programozási készségeimet. Egy programozási nyelv sem tökéletes, mert az egy adott területen

lévő kivállóság magával hordozza a más területeken lévő fogyatékosságokat is. Következésképpen egy programozó akkor jó programozó, ha minnél több nyelvhez fogékonyan ért, és kreatívan is tudja használni azokat az adott probléma megoldásához. A továbbiakban különös érdeklődéssel figyelem (és hobbi szinten gyakorlom is) a mobil operációs rendszerekre való alkalmazásfejlesztés egészét. Fő célom viszont, hogy továbbfejlesszem a meglévő tudásomat, megismerjem és tapasztalatot szerezzek azokból a piacképes technológiákból és módszerekből amelyekből később profitálhatok. (Scrum, agilis szoftverfejlesztés, minőségbiztosítás a szoftverfejlesztésben, C++, C#, szkriptnyelvek, mint a php, és MySql, valamint szerverek és operációsrendszerek [Linux] üzemeltetésében is szeretnék tapasztalatot szerezni.) Írta Teket Dávid. 2014-04-23. Budapest Az egész projekt elkészítése a szakdolgo zati dokumentációval 23 napot vett

igénybe Kapcsolat https://www.linkedincom/pub/teket-d%C3%A1vid/50/558/735 43