Az előző cikkben bemutattuk röviden a Xamarint, és telepítettük a Visual Studio-t az appfejlesztéshez szükséges pluginekkel. Itt a nyár, nincs is jobb egy kis strandolásnál, de hova érdemes menni? A cikksorozat hátralevő részeiben egy strandlistázó app példáján keresztül mutatom be a hatékony crossplatform mobilfejlesztés alapjait.

Mit fog tudni ez az app?

  • lista formájában prezentáljuk magyarországi strandok nevét, városát
  • egy részletező oldalon bemutatjuk a kiválasztott strand egyéb információit
  • JSON formátumban tárolt file-ból olvassuk be a strandok információját
  • egy ingyenes időjárás-előrejelző API segítségével megmutatjuk a strandoknál várható időjárást

A Xamarin lényege, hogy minél több kódot újrahasznosítva tudjunk appokat készíteni. Vegyük át először ennek a kódszervezésnek az alapjait!

Crossplatform alapok

A kódunk újrahasznosításának kulcsa a PCL (Portable Class Library) használata. Amikor létrehozunk egy új crossplatform projektet a Visual Studio-ban (FileNew ProjectTemplates / Visual C# / Cross-PlatformBlank App (Native Portable)), 4 alprojektet fogunk látni a Solution Explorerben.

Az App1 (Portable) ebben a példában a PCL-ünk. Ez tartalmazza majd az összes, platform-független kódunkat. Amikor az Android, vagy a WinPhone projektünkkel dolgozunk, a PCL-t referenciaként fogjuk betölteni az adott projektbe, így minden abban megvalósított logikát elérünk majd az összes platformon.

Mit tartalmaz általában egy PCL?

  • adatok eléréséért felelős modulok, mint pl. SQLite adatbázis interface, file-elérés, hálózati műveletek (adatok le-és feltöltése szerverre, 3rd party szolgáltatások elérése).
  • adatmodellek: az app logika alapvető építőkövei, a megvalósított funkciókhoz szükséges adatok logikus tárolási egységei
  • “üzleti logika”: az app lényegét, végső célját megvalósító osztályok, és általános vezérlőmodulok
  • interface definíciók: sokszor szükségünk van arra, hogy platform-specifikus szolgáltatásokat érjünk el a telefonokon (pl. GPS, vagy kamerakezelés). Ilyenkor egy interface-ben össze tudjuk foglalni a szükséges működés paramétereit, és az interface-t felhasználva közös kódban tudjuk felhasználni a platform-specifikus műveletek végeredményeit.

A fenti rövid app-specifikációnk alapján, a mi esetünkben a PCL-ben ezeket a funkciókat fogjuk megvalósítani:

  • adatelérés:

    • interface a lokálisan tárolt strand információs file beolvasásához
    • 3rd party REST API alapszintű használata a HttpClient használatával
  • adatmodellek:

    • strand
    • időjárás-előrejelzés
  • üzleti logika:

    • strandok listájának elérhetővé tétele
    • egy adott strand részletes információinak elérhetővé tétele
    • strandokhoz tartozó időjárásadatok elérhetővé tétele
Android alapok

Mivel natív appokat készítünk a Xamarin segítségével, fontos tisztában lennünk a platformok logikájával és sajátosságaival, amikre fejlesztünk. Ebben a részben az Android app alapjait is lefektetjük, így egy gyors áttekintőt magáról az Androidról még a fejlesztés előtt érdemes átvennünk.

API Levels

Évről évre a Google frissíti az Android operációs rendszert, ami újabb és újabb SDK-k megjelenésével is jár. Amikor appot fejlesztünk, érdemes fejben tartanunk azt, hogy országonként eltérő az Android verziók elterjedtségi szintje, és érdemes előző verziókat is támogatnunk az appunkkal, nem csak a legfrissebb változatokat. Ez a gyakorlatban azt jelenti, hogy ha az appban olyan SDK funkciót akarunk elérni, ami csak újabb Android verziókon elérhető, fel kell készülnünk arra az esetre, ha az appunk egy régebbi Android verziót futtat (pl. nem tesszük elérhetővé az adott funkciót egyáltalán, vagy fejlesztünk belőle egy olyan változatot, ami a régebbi verzión is fut.) Az alábbi kép mutatja a Google által közzétett legfrissebb, globális statisztikát a jelenlegi Android verziók elterjedtségéről.

  • Marshmallow: 6.0
  • Lollipop: 5.0 - 5.1
  • KitKat: 4.4
  • JellyBean: 4.1.x - 4.3
Activity Lifecycle

Az Activity-k az Android appok alap építőelemei. Leegyszerűsítve, általában egy Activity-t meg tudunk feleltetni az app egy-egy screenjének. Bármelyik, erre a célra beregisztrált Activity felhasználható belépési pontként egy app indításához, de általában a gyakorlatban egyetlen ilyen induló Activity-vel rendelkezik egy app.

Az Activity-knek van egy életciklusa, indítástól a leállásig:

alt text

  1. Miután elindítunk egy Activity-t, az a futó állapotba, és előtérbe kerül, ez jelenik meg a telefon kijelzőjén.
  2. Ha egy másik Activity részlegesen, vagy transzparensen kerül a futó Activity fölé, akkor a takart Activity Pause állapotba kerül. Ilyenkor még az Activity megtartja a jelenlegi állapotát, objektumait, változóit.
  3. Ha egy Activity-t egy másik teljesen elfed (pl. új képernyőt mutatunk), a háttérbe kerül az Activity. Ilyenkor a saját állapotát egy ideig még megtartja, de az Android keretrendszer bármikor dönthet úgy, hogy memóriafelszabadításra van szükség, ilyenkor ezek az állapotok és adatok elvesznek. Ha fontos az állapot megőrzése, ennek az elmentéséről, majd a későbbi visszatöltésről külön kell gondoskodnunk.
  4. Ha egy screenről az Android Back gomb nyomásávál navigálunk el, megáll az adott screen Activity-je.
  5. Ha az Android keretrendszernek több memóriára van szüksége, a leállított Activity-t teljesen bezárja, törli a memóriából.
  6. Egy leállított activity-t lehet Restartolni

A Xamarin frameworkkel az összes Android lifecycle eseményt elérjük, így ha szükség van rá, minden állapotátmenetre tudunk reagálni. A legfontosabbak:

OnCreate(Bundle bundle)

Ez hívódik meg egy Activity létrehozásakor. A képernyő felépítéséhez, változók inicializálásához hasznos esemény. Bementő paraméterként egy Bundle objektumot kaphat. A Bundle egy dictionary, amit az Activity-k saját állapotuk tárolására majd későbbi visszatöltésére, vagy Activity-k közötti kommunikációra, adattovábbításra használnak.

OnStart()

Ez az OnCreate után, de még az Activity megjelenítése előtt hívódik meg. Ha frissítenünk kell értékeket a képernyőnkön, itt érdemes megtenni. Ha az Activity-t az Android keretrendszer restartolja, akkor is meghívódik ez az esemény.

OnResume()

Ez akkor hívódik meg, amint az Activity késszé válik a felhasználóval történő interakcióra (akár frissen indított, akár újraindított, vagy háttérből újra előjövő Activity-ről van szó).

OnPause()

Ha az Activity-t a rendszer készül a háttérbe rakni, vagy elfedni, ez az esemény hívódik meg. Ha fontos eltárolni a jelenlegi állapotot, azt itt érdemes megtenni, illetve fölöslegessé váló objektumokat is törölhetünk már itt. Fontos, hogy amilyen műveleteket az OnPause-ban elvégzünk, annak megfelelő műveleteket kell az OnResume-ban is végrehajtani. (elmentett adatok újra beolvasása, objektumok létrehozása).

UI, Layoutok

Az Activity-k alapvetően egy-egy screent képviselnek. Ahhoz, hogy UI elemek a képernyőre kerüljenek, vagy kódból, vagy AXML-ből (Android XML) kell ezeket az elemeket felépítenünk. A legtöbb esetben az AXML megoldás javasolt, mi is ezt fogjuk most követni, ahol csak lehet.

A képernyők strukturálásához az Android számos layoutot ad, hogy könnyen el tudjuk helyezni a UI elemeinket. Nem mutatom be az összes lehetséges layoutot, csak a saját appunk elkészítéséhez szükségesekről lesz most szó. A layout magába foglalhat további layoutokat, vagy UI építőelemeket, mint pl. TextView-t, Button-t, stb.

Linear Layout

Függőlegesen, vagy vízszintesen fogja egymás után pakolni a layoutba ágyazott elemeinket. Ezt fogjuk használni a strand-infó részletező képernyőjén.

A fenti kép egy példa 3 Linear Layoutból felépített képernyőre. Van egy root, befoglaló layoutunk, ami függőlegesen rendezi a saját elemeit. Az első eleme egy Linear Layout, ami vízszintesen rendezi a saját elemeit. Ebben találjuk a színes téglalapokat. A befoglaló layout következő, függőlegesen rendezett eleme szintén egy layout, ami ugyanúgy függőlegesen rendezi a benne foglalt elemeket, és elhelyeztünk benne 4 darab TextView-t.

List View

Akár hosszú, akár rövid listázandó tartalmak megjelenítését könnyítő layout. Egy scrollozható View-t biztosít, amibe egy Adapter-en keresztül továbbítjuk a megjelenítendő adatokat.

Minden egyes sor egy-egy külön View, ami vagy egy Android keretrendszer által adott, beépített felépítésű elem, vagy egy teljesen saját kinézetet biztosító, saját kód. Azért fontos ListView-t használnunk főleg hosszabb listáknál, mert a memóriahasználata optimalizálva van. Ha van egy több száz, vagy ezer elem hosszú listánk (pl. Contact lista), fölösleges mindnek View-t készíteni, hiszen egyszerre nem fér ki több 8-10 darabnál egy képernyőre. Amikor scrollozunk a listában, a korábban elkészített, de már a képernyőn nem látszódó View-k újrahasznosítódnak, ezáltal gyors, optimális, tetszőleges méretű listákkal tudunk dolgozni.

Theme-ek

A theme tulajdonképpen egy szabálygyűjtemény az egyes UI elemeink alap kinézetének meghatározására. Általában egy adott UI elemet egyszer akarunk design-olni, és azt minél többször újrahasználni. Ebben nyújt segítséget a theme, ami egyrészt az Android által előre készített design-csomagokat tartalmazza, másrészt ezeket mi még testreszabhatjuk, amennyiben szükségünk van rá. Az Android 5.0-ban bevezetett Material design-t követő 3 különböző theme-et is biztosít a keretrendszer, Android 5.0-tól (API Level 21) kezdve:

  • Theme.Material: Ez az alapértelmezett, alapvetően sötét színekkel operáló csomag
  • Theme.Material.Light: Ez egy világos változat
  • Theme.Material.Light.DarkActionBar: ez a világos változattal megegyező theme, annyi különbséggel, hogy itt az ActionBar sötét.

Egy theme-et használhatunk akár az egész appunkban, de Activity-nként is dönthetünk úgy, hogy más theme használatára van szükségünk.

Ennyi bevezető után már neki tudunk látni a feladatnak! Hozzunk létre egy új crossplatform projektet Visual Studio-ban, legyen a neve BeachApp: FileNew ProjectTemplates / Visual C# / Cross-PlatformBlank App (Native Portable), és kezdődhet a fejlesztés!

PCL váz

A BeachApp (Portable) projektben lefektetjük az alapokat.

Modell
  1. Hozzuk létre a strand modell osztályunkat. Egyelőre ezeket az adatokat fogjuk tárolni egy-egy strandhoz:

    • név
    • város
    • cím

    Jobbklikk a Solution Explorerben a BeachApp (Portable) projekten, majd AddNew ItemClass. A Class neve legyen Beach, majd hozzuk létre a String property-ket a modellen. A rendkívül egyszerű osztályunk így néz ki:

namespace BeachApp.Model {     public class Beach {         [JsonProperty("name")]         public String Name { get; set; }         [JsonProperty("city")]         public String City { get; set; }         [JsonProperty("address")]         public String Address { get; set; }     } }

Érdemes külön namespace-be szerveznünk a modelleinket, interface-eket, managereket, bár ez nem egy kötelező lépés. A JsonProperty a deszerializációt teszi majd lehetővé egy rendkívül egyszerű módszerrel, erre a 4. lépésben kitérünk.

  1. Hozzuk létre a file beolvasás interface-ét, szintén a PCL projektünkben. AddNew ItemInterface. A neve legyen IFileLoader. Definiáljuk az egyetlen funkciót, amire majd szükségünk lesz, ez pedig a file beolvasásából származó Stringet visszaadó függvény.
namespace BeachApp.Interface {     public interface IFileLoader {         String LoadFileAsString(String fileName);     } }

Ennek az lesz az előnye, hogy az interface-re tudunk hivatkozni majd a PCL-ből, de a funkció igazi megvalósítása külön-külön lesz implementálva az Android és a WinPhone projektekben. A beolvasott Stringből Beach objektumokká alakítást már a PCL-ben végezzük el.

  1. Hozzuk létre a BeachManager osztályt (AddNew ItemClass, név: BeachManager, aminek az alábbi feladatai lesznek egyelőre:
    • Stringből Beach objektumokká alakítás
    • Beach objektumok listájának elérhetővé tétele az app számára
namespace BeachApp.Manager {     public class BeachManager {         public List<Beach> Beaches { get; private set; }                 public BeachManager(IFileLoader fileLoader) {             var result = fileLoader.LoadFileAsString("beaches.json");             ParseBeachData(result);         }         void ParseBeachData(String jsonString) {         }     } }

A BeachManagernek a konstruktorban átadjuk az adott platformon megvalósított file-beolvasót, ennek segítségével kiolvassuk a beaches.json file-ban tárolt adatokat, majd a ParseBeachData segítségével populáljuk a Beaches listánkat.

  1. JSON konverzió a JSON.NET keretrendszerrel. A Newtonsoft által fejlesztett JSON parse-oló az egyik legnépszerűbb ilyen csomag, mi is ezt fogjuk használni a projektben, Nuget formájában. A PCL projekt References folderén jobbklikk, majd Manage NuGet Packages. A Browse tabon keressünk rá arra, hogy “newtonsoft”, válasszuk ki a találati listából, majd Install.

Amennyiben sikeres volt a telepítés, a References alatt meg is jelent a Newtonsoft.Json csomag.

alt text

Ezután a ParseBeachData függvényünket be tudjuk fejezni:

void ParseBeachData(String jsonString) {     try {         Beaches = JsonConvert.DeserializeObject<List<Beach>>(jsonString);     }     catch (Exception e) {         Debug.WriteLine(e.Message);     } }

A JsonConvert segítségével a stringet deszerializáljuk a beach-ek listájáva. Érdemes try-catch-ben végeznünk a műveletet, ha bármilyen okból kifolyólag nem sikerül a konverzió, exceptiont fog dobni a parse-oló. A deszerializáció a Beach modell osztályban lévő JsonProperty attribútumok segítségével párosítja össze a JSON-ben tárolt, és a modellben lévő adatstruktúrákat.

Egyelőre ennyi funkció elég a PCL-ben, jöhet maga az Android app!

Android app váz
  1. Az Android appot válasszuk ki az alapértelmezett projektnek a Set as StartUp Project segítségével a Solution Explorerben.
  1. A projektünk már tartalmaz is egy Activity-t, MainActivity néven. Nyissuk meg a file-t, ezt fogjuk használni belépési pontként mi is.

    A MainLauncher Attribute-tal regisztráljuk be az Activity-t, hogy az app indulásakor ez töltődjön be először. A Label az appikon alatti nevet, míg az ikon magát az appikon kinézetét állítja be.

    [Activity (Label = "BeachApp.Droid", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity {

    Az OnCreate-ben látjuk, hogy betöltjük a View-t a SetContentView függvény segítségével.

        protected override void OnCreate (Bundle bundle) {         base.OnCreate (bundle);         // Betöltjük a view-t a "main" layout resource-ból         SetContentView (Resource.Layout.Main);
  2. Nyissuk meg a Main.axml file-t a Resourcelayout mappában, ami a View kinézetét írja le. Mind a beépített vizuális designer-rel, mind közvetlen source módban szerkeszthetó az axml file, mi most a hagyományos, source módnál maradunk.

Ha túl régi Android SDK verziónk van telepítve, és a Visual Studio hibát dob amikor megpróbáljuk megnyitni az axml file-t, frissítenünk kell ezeket a csomagokat. Ilyenkor nincs más teendőnk, mint a ToolsAndroidAndroid SDK Manager alatt feltelepíteni a legfrissebb Android SDK Tools, és Android SDK Platform-tools csomagokat.

A Microsoft törekszik arra, hogy minden új Android, vagy iOS platform release hivatalos megjelenéseivel egyidőben frissüljön a Xamarin keretrendszer is, és támogassa a legújabb API-kat. Mivel az Android SDK Managerben található csomagokat a Google tartja karban, itt előfordulhat annyira friss verzió egy új változat kijövetelekor, amit még nem támogat a Xamarin, így érdemes néha várnunk, és csak akkor frissíteni csomagokat, amikor már a Xamarin is támogatja azokat, és amennyiben valóban szükségünk van a frissebb csomagokra.

  1. Az alapból a file-ban található UI elemekre nem lesz szükségünk, rakjunk a képernyőre egy TextView-t, és egy List View-t helyettük! Így fog kinézni a file tartalma:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical"     android:layout_width="fill_parent"     android:layout_height="fill_parent">     <TextView         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="Strandok"         android:textSize="24dp"         android:background="#00000000"         android:textColor="#009BD9"         android:textStyle="bold"         android:padding="5dp" />     <ListView         android:id="@+id/List"         android:layout_width="fill_parent"         android:layout_height="fill_parent"         android:cacheColorHint="#00000000" /> </LinearLayout>

Nézzük meg, mit is jelentenek a felhasznált paraméterek.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical"     android:layout_width="fill_parent"     android:layout_height="fill_parent">

Ez a befoglaló layout-unk. Úgy paraméterezzük fel, hogy a benne lévő elemek függőlegesen (vertical) rendeződjenek egymás alá. A layout szélességének, és magasságának pedig a fill_parent opciót állítjuk be, azaz a teljes képernyőt elfoglalja majd a layout-unk.

Ezután következik egy TextView, amit a listánk címének használunk majd:

<TextView         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:text="Strandok"         android:textSize="24dp"         android:background="#00000000"         android:textColor="#009BD9"         android:textStyle="bold"         android:padding="5dp" />
  • szélességre azt mondjuk, hogy legyen olyan széles, mint a szülő-eleme (a befoglaló layoutunk, ami viszont a teljes képernyőt elfoglalja szélességben)
  • magasságra azt mondjuk, legyen pont akkora, amekkora magasságot a tartalom megkíván (wrap_content). Ez egy szövegmező esetén a betűméret nagyságától, és a szöveg hosszától függ.
  • beállítjuk a szöveget
  • beállítjuk a betűméretet, dp-ben.

A dp jelölésről röviden annyit érdemes tudni, hogy ez a különböző Android készülékek képernyőfelbontását és fizikai képernyő méretét figyelembe véve számolja ki, hogy az adott készüléken mekkora is legyen a megjelenítendő pixelméret. dp-ben érdemes a legtöbb szituációban méreteket megadnunk ahhoz, hogy a különböző eszközökön konzekvensen jelenjenek meg a UI elemeink.

  • háttérszínkód, és szövegszínkód
  • padding beállítása: ekkora helyköz lesz az aktuális, és a következő elem között a képernyőn

Végül következik a listánk definiálása:

<ListView         android:id="@+id/List"         android:layout_width="fill_parent"         android:layout_height="fill_parent"         android:cacheColorHint="#00000000" />
  • az id megadásával egy hivatkozási nevet tudunk adni a UI elemünknek, aminek a segítségével később elérhetjük azt mind a C# kódból, mind az axml file többi részéből. Ez akkor hasznos, ha egyéb műveleteket akarunk még kódból elvégezni az adott elemen, vagy a többi UI elemünk pontos pozícionálásához hivatkoznunk kell erre az elemre.
  • a cacheColorHint abban segít, hogy ha egy hosszú listán gyorsan scrollozunk, a betöltődő elemek alapszíne megegyezik majd a listaelemek háttérszínével, így villódzásmentessé tudjuk tenni a scrollozást

Ezzel meg is van a listaképernyőnk alap layoutja!

  1. Bár az Android platform ad nekünk pár beépített lehetőséget List View-k sorainak a kinézetére, mi csinálunk egy saját View-t, ami egy-egy sorunkat majd megjeleníti.

A Solution Explorerben, a layout folderen jobbklikk, AddNew ItemAndroid Layout, a file neve pedig legyen BeachListRow.axml. A file tartalma legyen egy Linear Layout függőleges elrendezéssel, és tartalmazzon egyelőre 2 TextView-t.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:orientation="vertical"     android:padding="10dp">     <TextView         android:id="@+id/Name"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:textColor="#009BD9"         android:textSize="18dp"         android:textStyle="italic" />     <TextView         android:id="@+id/City"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:textSize="13dp"         android:textColor="#1ECCA1"         android:paddingLeft="15dp" /> </LinearLayout>

Ezzel létrehoztunk egy layoutot két címkével, amikre Name, illetve City néven tudunk majd kódból hivatkozni.

  1. Implementáljuk a PCL-ben definiált IFileLoader interface Androidos verzióját! AddNew ItemClass, a név legyen FileLoader. Az osztályunk természetesen IFileLoader-ből származik le, és megvalósítja a LoadFileAsString funkciót:
public String LoadFileAsString(String fileName) {             String response = default(String);             var assetManager = Application.Context.Assets;             try {                 var stream = new StreamReader(assetManager.Open(fileName));                 response = stream.ReadToEnd();             }             catch(Exception e)             {                 System.Diagnostics.Debug.WriteLine(e.Message);             }             return response;         }

As AssetManager segítségével tudunk megnyitni file-okat az Assets könyvtárban. Mint sok más műveletnél, itt is érdemes try-catch-ben végeznünk a beolvasást, majd visszaadjuk a végeredményt.

  1. Másoljuk be a beaches.json file-t az Assets könyvtárba (Az Assets folderen jobbklikk, AddExisting Item). Tesztelés céljából egyelőre 3 strandot tartalmaz csak ez a file. Ezután válasszuk ki a beaches.json file-t a Solution Explorerben, és a Properties ablakban állítsuk át a Build Actiont AndroidAsset-re.

  2. Hozzunk létre egy Adapter osztályt, ami a listánkat szolgálja majd ki soronként adatokkal! Az Android projekten jobbklikk, AddNew ItemClass, a neve legyen: MainAdapter.cs, és így néz ki az osztályunk:

    class MainAdapter : BaseAdapter {         List items;         Activity context;         public MainAdapter(Activity context, List items) : base() {             this.context = context;             this.items = items;         }         public override long GetItemId(int position) {             return position;         }         public override Beach this[int position] {             get { return items[position]; }         }         public override int Count {             get { return items.Count; }         }         //visszaadjuk az adott sorhoz tartozó View-t, adatokkal kitöltve         public override View GetView(int position, View convertView, ViewGroup parent) {             var item = items[position];             View view = convertView;             if (view == null) // ha nincs újrahasznosítható view, hozzunk létre egy újat                 view = context.LayoutInflater.Inflate(Resource.Layout.BeachListRow, null);             view.FindViewById(Resource.Id.Name).Text = item.Name;             view.FindViewById(Resource.Id.City).Text = item.City;             return view;         }     }

Ez az adapter osztály az alábbiakért felel:

  • lista hosszának meghatározása
  • listában adott index-hez tartozó objektum lekérdezése
  • adott sor-indexhez tartozó View rendelkezésre bocsájtása, és adatokkal való feltöltése
  1. Ezután nincs más dolgunk, mint a MainActivity-ben beállítani a List View-nknak az adaptert, és egy BeachManager objektumnak átadni az Androidos FileLoadert!
[Activity (Label = "BeachApp", MainLauncher = true, Icon = "@drawable/icon")]     public class MainActivity : Activity     {         ListView listView;         protected override void OnCreate (Bundle bundle)         {             base.OnCreate (bundle);             SetContentView (Resource.Layout.Main);             listView = FindViewById<ListView>(Resource.Id.List);         }         protected override void OnStart() {             base.OnStart();             var beachManager = new BeachManager(new FileLoader());             listView.Adapter = new MainAdapter(this, beachManager.Beaches);         }     }
  1. Indítsuk el az appot, és megjelenik a lista képernyőnk, a JSON file-ból beolvasott strandok listájával!

  2. Ahhoz, hogy a Material Design alapú theme-et fel tudjuk használni, egy minimum 5.0-s Android emulátort kell futtatnunk. Ha nem települt alapból ilyen, a Visual Studio Emulator for Android alkalmazást indítsuk el, és válasszunk egy emulator image-et a listából, ami Android Lollipoppot futtat.

Töltsünk le egy nekünk szimpatikus image-et.

Most már a Visual Studio-ban ki tudjuk választani az emulátorok közül az 5.0-t futtató változatot.

  1. Állítsuk be az egész appunkra a világos Material Design Theme-et, sötét ActionBarral. Nyissuk meg az androidmanifest xml file-t (Propertiesandroidmanifest.xml), és az application xml tag-ben specifikáljuk az android:theme-et
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android">     <uses-sdk android:minSdkVersion="15" />     <application android:theme="@android:style/Theme.Material.Light.DarkActionBar"></application> </manifest>
  1. Indítsuk el az appunkat az 5.0-t futtató emulátoron, és meg fog jelenni a listánk, világos háttérrel, ahogy szerettük volna.

Sikeresen vettük az első akadályt, a strandok listáját beolvassuk és megjelenítjük az Android appunkban!

A cikksorozat következő részében az Universal Windows Platform alapjait mutatjuk be, és ugyanígy elkészítjük a listánkat.