2016. június 06.

Kapcsolódás API-khoz Android platformon

10 perc olvasási idő

Kapcsolódás API-khoz Android platformon

Az API-hoz való kapcsolódás egyik lényeges eleme a mai mobil appoknak. Több könyvtár közül is választhatsz, majd implementálnod, optimalizálnod és tesztelned kell. Összefoglaltam milyen lehetőségek vannak és mire érdemes figyelni.

Mit szeretnék az API-tól?

Nem csak a backendet fejlesztő kollégának kell tudni, mi kell egy jó API-hoz, hanem a mobilfejlesztőnek is. Javaslatot, visszajelzést kell tudni adni az API készítése és használata közben. Egy mobil platform nem tudja nyújtani ugyanazt a teljesítményt, mint egy asztali. Nem csak a processzor, memória és az akkumulátor korlátozott, hanem maga a hálózat is az. Mivel állandóan mozgásban vagyunk, a hálózat is változik körülöttünk. 2G, 3G, 4G, LTE és WiFi között ugrálunk. Sajnos maga a kapcsolat típusa sem garantálja a hálózat sebességét. Ha egy buszmegállóba éppen beálló buszról mindenki az ott elérhető ingyenes WiFi-re ráugrik az elérhetetlen lesz. Ráadásul magáért az adatforgalomért is fizetni kell.
Ennek tudatában kell az API-t és az appot megalkotni, megtervezni.

1 lekérés képernyőként

Erre kell törekedni, azaz a felhasználói felületből kell kiindulni fejlesztéskor. Cél, hogy azokat az adatokat, amiket lát a felhasználó egyetlen lekérésből el tudd érni.

Képzeletbeli Karcsi kedvenc boltjainak listája egy felületen

A fenti felületen több mint 10 lekérést kell indítani a legrosszabb esetben, hogy Karcsi felhasználód kedvenc boltjait lekérd. Hiszen minden képet le kell szedned, a felhasználó nevét, a kedvenc bolt listát és annak elemeit.

Paraméterezhetőség

Ha a válaszban olyan mezők is vannak, amit nem használsz fel, akkor azok nem csak az adatforgalmat növelik, de a feldolgozást is lassítják. A legjobb az, ha valamilyen módszerrel leszűkítheted a visszakapott eredményt. Például url paraméterezéssel:
https://api.hu/bolt/azonosíto?mezok=nev,kedvencek_szama,kep

Denormalizálás

Ha egy válasz csak újabb lekéréssel értelmezhető, az baj. A fenti kedvencek bolt lista rosszabb esetben csak azonosító listát ad vissza:


{
  "bolt_azonositok" : [1234, 5432, 54325, 532, 54324]
}

Ebben az esetben neked kell a szerver adatbázisának tábláit összecsatolnod, ami a legrosszabb megoldás. Helyette az API-nak kellene értelmezhető adatokat visszaadnia.


[
  {
    "id" : 1234,
    "nev" : "tesco",
    ...
]

Ilyenkor már is megspóroltál egy hívást.

Könyvtárak

Amint megvan az API, eldöntheted, melyik könyvtárat használod hozzá. Ehhez tisztában kell lenned azzal, hogy milyen API hívások lesznek. Nem minden könyvtárban érhető el minden hívás vagy egyszerűen azok hibásak. Ilyen például fájlfeltöltés vagy a nagyobb méretű fájlok letöltése.

Alapvetően 2 lehetőség van, majd ezen belül lehet válogatni:

  • Alacsony szintű HTTP kliensek:
  • Apache HttpClient
  • HttpUrlConnection
  • OkHttp
  • Magasabb szintű könyvtárak:
  • Volley
  • Retrofit

Alacsonyabb szintű kliensek

Az Apache klienst a Google eltávolította a 23-as API-ból és a HttpUrlConnection használatát javasolja 9+ API szint fölött. A HttpUrlConnection mint alternatíva nem valami kellemes. Egy hiba felbukkanása esetén valamilyen kerülő megoldást kell alkalmaznod, vagy várhatsz a következő verzióra. Egy külső könyvtárnál, mint az OkHttp, a hibák javítása és a funkciók gyorsan jönnek, ezért érdemesebb azt választani.

Magasabb szintű kliensek

Alacsonyabb szintű kliens használatával neked kell minden kivételt lekezelni és a választ is feldolgozni. Követni kell a jó öreg programozási szabályt:
Hagyd, hogy a munka nehezét más végezze el helyetted.

Retrofit

A szerver végpontok metódusok, így ezeket könnyen használhatod a kódodban, melyeket egy interface annotálásával egyszerűen létrehozhatsz. Maga a Retrofit kezeli a szervertől kapott válasz átalakítását POJO osztályokká, ami még jobban megkönnyíti a dolgodat. Rengetegen használják így, van is dokumentációja.

Volley

A Google által létrehozott Volley-val kicsit több dolgod van. Csak pár előre megírt választípus van, és ezek létrehozásával indul a kérés. Például, ha XML-t szeretnél használni, akkor ennek kezelését neked kell megírni. Dokumentáció nem valami sok, inkább a Stackoverflow és maga a forráskód, amelyekre támaszkodhatsz. Hátrányai ellenére több funkciót tartalmaz, például beépített támogatás van a prioritást beállítani, és újrapróbálni a lekérést akár exponenciális visszalépéssel.

Implementáció

Itt két dolgot emelek ki, amire figyelni kell. Az egyik a szálkezelés, ami kicsit rafinált dolog Androidon. A másik pedig a lekérések optimalizálása.

Szálkezelés

Az egyik legnehezebb dolog, főleg a konfiguráció váltások miatt. A másik szálon indított hívásodat eldobhatod, amint elfordul a kijelző, vagy rosszabb esetben behal az alkalmazás. Ennek megoldására a hívás eredményét cachelni kell, vagy a konfiguráció váltást kell megfelelően lekezelni.

A leggyakrabban használt osztály az AsyncTask. Itt neked kell lekezelni azt az esetet, amikor eltűnik a felület, miközben fut a hívás. Azt is neked kell kezelni, ha meg akarod szakítani ennek a szálnak a futtatását.

RxJava is használhatsz, ahol a fel- és leiratkozás elintézi a megváltozó UI problémáját. Ennek a libnek az elsajátítása sajnos nem egyszerű, így többfős csapatban a munkát is megnehezítheti. Szerencsére mára már sok dokumentációt, blog posztot találhatsz róla.

Bármilyen megoldást is használsz, külön szál létrehozásánál mindig figyelj, hogy UI elemeket az ne tartalmazzon. Amennyiben mégis így teszel, a teljes felhasználói felület a memóriában maradhat, miközben a felhasználó már mást lát.

Optimalizáció

Nem szabad elfelejteni, hogy az API hívásokat is lehet optimalizálni. A hálózati hívások alkalmával, a hálózattal foglalkozó hardver feléled, majd elküldi a kérést. Ez után megvárja a választ, és még utána 20, vagy akár 60 másodpercig is bekapcsolva marad, fogyasztva az akkumulátort. Ez az egyik legtöbb akkumulátort használó elem a mobiltelefonban.

Batching

Amennyiben a várakozási időszakban újabb kérést indítasz, az egész ciklus újraindul. A megoldás, hogy több hívást egyszerre indíts el.

A kulcs ehhez, hogy különbséget tudj tenni azok között a dolgok között, melyeknek most kell történnie és melyeknek elég később. A szerver felé küldött adatok a későbbi kategóriába tartoznak. Nem kell a szervernek azonnal értesülnie arról, hogy valaki kedvencnek jelölt valamit a felületen.

Ezeket a hívásokat külső könyvtárak segítségével könnyen kezelheted:

A GcmNetworkManager-hez Google Play Services szükséges, és nem biztos, hogy fel van telepítve, vagy a legfrissebb található a felhasználó telefonján. Ez 21-es API-tól a JobSchedulert használja.

Polling

Időnkénti frissítéseket is ki lehet váltani például push használatával. Nem kell 2 percenként kérdezgetni a szervert, hogy van frissítés. Jobb, ha a szerver értesít a változásról. Ha egy ilyen megoldás nem jöhet szóba, ravaszabb is lehetsz a frissítéssel kapcsolatban. Google API segítségével detektálhatod például, hogy éppen milyen tevékenységet végez a felhasználó és eltolhatod a frissítést. Futás közben biztos nem fogja olvasgatni a telefonját. Ha viszont rárakta a töltőre, bátrabban kérdezheted meg a szervert.

Tesztelés

Tesztelés az egyik legfontosabb dolog hálózat hívásoknál (is). Éles szerveren a legtöbb hibát nem tudod előidézni, így nehéz felkészíteni az alkalmazást az esetleges hibákra. Összetettebb kód esetében több ponton is hibába eshetsz, érdemes tehát valamilyen jó rendszert alkotni.

Egy hívás esetén ezek a főbb pontok:

  1. Kapcsolódás a hálózathoz
  2. Kapcsolódás a szerverhez
  3. Megkapod a választ
  4. Válasz feldolgozása

Ennek megfelelően kell tesztelni:

  1. Nincs hálózat
  2. Nem elérhető a szerver
  3. Hibás válasz jön vissza
  4. Hiba történik a válasz feldolgozása közben

Retrofit esetén könnyű unit és integrációs teszteket csinálni. Használhatsz egy előre megírt Mock osztályt, aminek megadhatsz választ, HTTP kódot, késleltetést és egyéb hasznos dolgokat.

Volley esetében ez nehezebb. Vannak mock osztályok, amiket a gitről kell összeszedni és kibogarászni.

Összetettebb API-kra a WireMock nevű eszközre vess egy pillantást. Ez tényleges szervert, HTTP szervert hoz létre, ami a kéréseidre adja majd vissza a válaszokat. Olyan hasznos funkciója is van, mint a kérések rögzítése. Curl parancsok eredményeit el tudja tárolni, majd ez alapján válaszol. Mivel külön könyvtárat kell behúzni hozzá és még saját szervert is indít, ezért még nem használtam.

A hálózati hívások debuggolásához proxy szervert is használhatsz. Charles Proxy, Fiddler és mitmproxy a legnépszerűbbek.

Erről beszéltem az ITrend meetupon, melynek diái:

Vaszil Ádám

Már sok-sok éve szeretne programozó lenni, de mivel ennyi nyelvet nehéz megtanulni, ezért inkább csak a Javara koncentrál.

Vaszil Ádám

Hozzászólások