Skip to main content
Témakör:

Perifériaillesztés Android-eszközökhöz – 1. rész

Megjelent: 2014. április 11.

Microchip AndroidNapjaink mobil eszközeinek képességei a kö­zelmúltnak azokkal a PC-ivel mérhetők össze, amelyekhez számtalan egyedi perifériaillesztést és ezen keresztül akár ipari vagy más profes­szionális alkalmazásokat is megvalósítottak a fejlesztők. Kézenfekvő az ötlet, hogy a mindig „kezünk ügyében levő” okostelefon vagy tablet – és azok legelterjedtebb operációs rendszere, az Android – is hasonló megoldások alapjául szolgálhasson. Ehhez ad ötleteket a Microchip Technology szakértőjének cikke.

 

A mobiltelefonokat és tableteket ma már egyre gyakrabban kezdik beágyazott platformként alkalmazni. Erre a „PC-szerű” operációs rendszeren kívül az is bátorítja a fejlesztőket, hogy rendszerint többmagos processzor vezérli őket, és a többszálas programvégrehajtás is megkönnyíti több alkalmazás egyidejű futtatását. Ezzel például többféle adatátviteli funkció is megvalósulhat, miközben jól ismert és kényelmes grafikus felhasználói interfészfelülettel kezelhető alkalmazások futnak az eszközön. Ezen lehetőségek hatására a felhasználók magasabb szintű elvárásai fogalmazódnak meg, a fejlesztők számára pedig több lehetőséget, de igényesebb feladatokat is jelent.
A lehetőségek között az a legkézenfekvőbb, hogy a mobil készülék illeszthető más elektronikus eszközökhöz, mint például a személyi edzésre szolgáló gépekhez vagy orvosi célú, a testi állapotot felügyelő  készülékekhez. Az ilyen feladatok megoldásának nehézsége abban áll, hogy az új mobil alkalmazások fejlesztése sokféle tervezési tapasztalatot tételez fel, amelyek közt csak egy az, hogy a fejlesztő ismerje a kisebb teljesítményű processzorok alkalmazásfejlesztésének sajátosságait.

A többszálas végrehajtás

A többszálas programvégrehajtás lényegének ismerete nélkülözhetetlen a mobil alkalmazások fejlesztői számára, mert ez a feltétele az egyidejűleg több, egymástól független program végrehajtási képességének. A többszálas végrehajtás (threading) a programvégrehajtás olyan felosztása, amelyben (legalább) két kódkészlet hajtódik végre egymástól függetlenül. Míg az egyik kódsorozat egy esemény bekövetkezésére vár, a többi szál végrehajtása tőle függetlenül, zavartalanul futhat tovább. Enélkül az alkalmazás felhasználói interfésze látszólag „lefagyna”, és nem válaszolna a felhasználói beavatkozásokra, miközben a mobil készülék felcsatlakozik a webre, vagy a Bluetooth- vagy USB-interfésszel hozzá illesztett készülék válaszára vár. Az ilyen események előre nem látható ideig blokkolhatnák a felhasználói interfész használatát.

 

Microchip1 web mod

1. programrészlet: Szinkronizált funkciók

 

Microchip2 web mod

2. programrészlet: A synchronised kulcsszó használata

 

A többszálas végrehajtás (multithreading) azonban felveti azt a programfejlesztési problémát, hogy a szálak konkurens módon (az eszköz erőforrásaiért „versenyezve”) futnak. Ha két vagy több szál fut egyidejűleg és egymástól függetlenül, nagyon bonyolult adathozzáférési szituációk keletkezhetnek. Például akkor, amikor két szál közötti adatátvitelre van szükség, vagy amikor ugyanazt az adatot két szál olvassa vagy módosítja. Mivel a szálak végrehajtási ideje a programfejlesztés periódusában előre nem jelezhető, előfordulhat, hogy az egyik szál módosítja azt az adatot, amelyet a másik éppen olvas.

A Java ezt a problémát a synchronized kulcsszó alkalmazásával oldja fel, amely lehetőséget ad a fejlesztőnek, hogy egy szál a programfutás bizonyos szakaszaiban kizárhassa egy megosztott objektum használatát más szálak számára. Ez azt jelenti, hogy amint egy szál belép a „szinkronizált” programrészbe, a többi szál számára ez nem lehetséges mindaddig, míg az első szál el nem hagyta a programrészt. Az 1. programrészletben a szinkronizált funkciókat arra használjuk, hogy az egymástól függetlenül módosítható a és b változók összege a programvégrehajtás sorrendjétől függetlenül ugyanazt az eredményt adja.
Szinkronizáció nélkül lehetséges lenne, hogy az egyik szál olyan­kor hívja a getSum() funkciót, amikor a másik szál éppen ott tart az updateVariables() funkció végrehajtásában, hogy már megtörtént az a változó növelése, de még nem került sor a b változó csökkentésére. Emiatt a getSum() funkció „össze nem tartozó” a és b változókat ad össze, nyilvánvalóan téves eredményt adva mindaddig, míg az updateVariables() funkció végrehajtása be nem fejeződik.
A 2. programrészlet azt mutatja, hogyan lehet ugyanezt a hatást elérni, ha a szinkronizált függvények helyett szinkronizált szekciókat használunk. A szinkronizált szekció használata megengedi a szülőobjektumban a többi változó és funkció használatát, mivel a kizárólagos használatot nem az egész objektumra, hanem csak az a változóra érvényesítettük. Mivel a szinkronizáló utasítások alkalmazása kissé bonyolult és könnyen elhibázható, használatuk különös gondosságot igényel.
A Java-nyelv handlerek [1] és üzenetek útján azt is lehetővé teszi, hogy az adatokat vagy eseményeket biztonságosan lehessen átadni az egyik szálból a másikba. Egy handler nagyon hasonló egy postaládához. A handler belsejébe üzeneteket (message) is elhelyezhetünk, amelyek közül az első akkor válik láthatóvá a fogadó szál számára, amikor a küldő szál már befejezte a handler tartalmának módosítását. Ezért ez a módszer biztonságosan továbbít eseményeket és adatokat a szálak között. A handler és az üzenet használatára a 3., 4. és 5. programrészlet mutat példát.

 

Microchip3 web

3. programrészlet: Egy üzenetként használt objektumosztály létrehozása

 

Microchip4 web mod

4. programrészlet: Üzenet létrehozása és elküldése egy handler számára

 

Microchip5 web mod

5. programrészlet: Egy üzenet vételére és dekódolására alkalmas handler megvalósítása

Az életciklus közbeni változások újradefiniálása

Az Android kezelői beavatkozásai és alkalmazásai a programfutás közben megváltoznak (ún. életciklus-változásokon [2] mennek keresztül) az okostelefonon vagy táblagépen történt változások hatására. Amikor alkalmazást fejlesztünk az Android operációs rendszerre, fontos megértenünk, hogy ezek az életciklus-változások még olyan egyszerű felhasználói beavatkozásokat sem hagynak érintetlenül, mint a gép elfordításakor a kijelzési kép elfordulása, egy virtuális billentyűzet eltávolítása a képernyőről vagy akár egy telefonhívás fogadása vagy elutasítása. Ez azt jelenti, hogy előfordulhat, hogy egy rendszererőforrást, amelyre egy kezelői beavatkozásra való reagáláshoz szükség van, az életciklus bizonyos fázisaiban deaktiválni kell. Például gyakran használjuk az üzenetszórásos (broadcast) vevőfunkciót, amely arra szolgál, hogy bizonyos események megtörténtét detek­tálja az USB-buszon, még akkor is, amikor az eszköz lekapcsolódott.
A broadcast vevőfunkció viszont szükségszerűen „regisztrálatlan” addig, amíg az alkalmazás felfüggesztett állapotban van, és újra fel kell iratkoznia a buszra, amikor az alkalmazás folytatódik.
Az Android operációs rendszer módot ad arra, hogy átdefiniáljuk az egyes eseményekre adott alapértelmezett választ. Ezen a módon a fejlesztők tetszőleges funcionalitásokat adhatnak meg azokhaz az életciklus-átmenetekhez (1. ábra). Egy életciklus-funkció felüldefiniálására használjuk egyszerűen az állapot nevét funkcióként az @Override kulcsszót követően (6. programrészlet). 

 

Microchip6 web mod

6. programrészlet: Az onResume() funkció átdefiniálása

 

 Microchip abra mod

1. ábra Egy Android-aktivitás életciklusa

 

Ha egy életciklus-funkciót átdefiniálunk, mindig használjuk a super kulcsszót annak a szülőfüggvénynek a meghívásakor, amelyet át akarunk definiálni. Ez teszi lehetővé, hogy a függvény más helyről történt hívásakor annak eredeti definíciója maradhasson érvényben még az életciklus-átmenet után is. Ennek elmulasztása akár az alkalmazás összeomlását vagy a betöltődésének meghiúsulását is eredményezheti. Az alkalmazás létrehozásával összefüggő életciklus-változások (pl. onCreate(), onStart(), onResume()) idején a felüldefiniált függvények (a super kulcsszóval) tipikusan a funkció kezdetén hívódnak meg. Az alkalmazás lebontásával összefüggő onPause(), onStop() és onDestroy() függvényeknél pedig a funkció végére jellemző a felüldefiniált (super kulcsszavas) hívás.
A különféle életciklus-átmenetek kezelésének egyik lehetséges módszere az, hogy az átmeneteknél szükségessé váló változások lebonyolítását egy szolgáltatásra (service) bízzuk. Adatkommunikációs objektumokhoz kapcsolódó szolgáltatást arra lehet használni, hogy többféle aktivitást engedjünk meg az  egyazon adatkapcsolaton osztozó tevékenységeknek.

Vezetékmentes kommunikáció

A mobil készülékek három legjellemzőbb adatátviteli formája az USB, a Bluetooth és a WiFi. Ezen módszerek részletei azonban függenek az operációs rendszer verziójától és a mobil készüléken rendelkezésre álló hardveradottságoktól.
A WiFi valószínűleg a legkönnyebben használható és a legjobban dokumentált interfész az alkalmazásfejlesztéshez. Ha az illeszteni kívánt tartozékban beépített http-szerver is van, az okostelefon vagy tablet böngészője arra is használható, hogy ne kelljen a mobil eszközre egyedi alkalmazást fejleszteni. Léteznek ezenkívül különféle telnet/ftp-alkalmazások is, amelyek ugyancsak feleslegessé teszik az egyedi alkalmazás kidolgozását. Ha viszont mégis valamilyen ok szükségessé tenné ilyen „célalkalmazás” fejlesztését, ez felépíthető a Java beépített hálózati alkalmazási interfésze (network API) segítségével, amelynek használatát bőséges irodalom támogatja. Ezenkívül mégis van egy kimondottan Android-specifikus szoftvermegoldás, amelyet az alkalmazásba kell beleépíteni, hogy az képes legyen a hálózati API használatára. Az AndroidManafest.xml fájlban a hálózati API-hoz hozzáférő tevékenységnek egy programsorral kell engedélyezni a hozzáférést (7. programrészlet). Annak, hogy egy androidos készülékhez WiFi segítségével illesszünk valamilyen tartalmat, az a legfontosabb korlátja, hogy az Android jelenleg még nem támogatja az ad-hoc hálózatok létrehozását, azaz már előzőleg léteznie kell valamilyen vezetékmentes hálózatnak, mielőtt a WiFi-interfészű tartozékot használatba vennénk. Ez teljesen reális és elfogadható követelmény bizonyos alkalmazásoknál – például egy lakástermosztátnál, amely állandó WiFi-kapcsolatban áll a vezetékmentes routerrel, de általában nincs realitása semmilyen mobil tartozék esetében.
A különféle Android-verziók más és más Bluetooth-eszközöket támogatnak. Az Android 2.x0 (Eclair, Froyo, Gingerbread) alapértelmezésben a Serial Port Profile (SPP) képességgel rendelkezik (bár nem minden készülék alkalmas erre). Az SPP-profil azért használható jól az egyedi alkalmazások fejlesztésére, mert nincs előredefiniált adatformátuma. A speciálisabb tartozékokra tekintettel a 3.x-verzióban (Honeycomb) bevezették a Bluetooth beszélőkészlet (headset) és az Advanced Audio Distribution Profile (A2DP) támogatását, míg a 4.x verzió (Ice Cream Sandwich, Jelly Bean és Kitkat) az egészségügyi felhasználásra szánt Health Device Profile (HDP) profillal is kiegészült.

 

Microchip7 web mod

7. programrészlet: Ezzel a sorral engedélyezhető az internethozzáférés az alkalmazás számára

USB-kommunikáció

Az USB az egyik legújabb módszer, amellyel Android-készülékekből adatokat tölthetünk le. Az Android 2.3.4-verziója előtt az USB-port kizárólag a gyártó számára volt fenntartva, ezért nem volt elérhető az alkalmazásfejlesztők számára. Az Android 3.1-ben vezették be az USB Host API-t, amely lehetővé tette a fejlesztők számára, hogy szabványos USB-perifériákat illesszenek az erre alkalmas Android-készülékekhez. Az operációs rendszernek beépített támogatást tartalmaz néhány USB-eszközosztályra, mint amilyen a Human Interface Device (HÍD) és a Mass Storage Device (MSD) is. Ezek a beépített meghajtóprogramok (driverek) további illesztés nélkül teszik lehetővé ezeknek az eszközöknek a használatát. Azokhoz a perifériákhoz, amelyekhez nem létezik beépített, szabványos támogatás, az USB Host API-ban található egyszerű és alacsony szintű API-készlet teszi lehetővé az alkalmazásfejlesztőknek, hogy készüléket csatlakoztas­sanak USB végpontokra, és azon át kommunikáljanak (8. programrészlet).

 

Microchip8 web

8. programrészlet: Felcsatlakozás, és egy csomag elküldése az USB Host API segítségéve


Ahhoz, hogy engedélyt kapjon az USB Host API használatára, az alkalmazásnak az AndroidManafest.xml fájlban kell deklarálnia annak használatát (9. programrészlet).

 

Microchip9 web

9. programrészlet: Ezzel a sorral engedélyezhető egy alkalmazás számára az USB Host API használata


Ahhoz, hogy egy alkalmazás automatikusan elinduljon, ha egy kiválasztott perifériának az USB-porthoz történt csatlakozását ész­leli, egy eszközszűrőt (device filter) kell beállítani. Ebből a célból az AndroidManafest.xml fájlban egy „szándékszűrőt” (intent filter) kell létrehozni (10. programrészlet) és az USB_DEVICE_ATTACHED eseményhez társítani, és mindezt egy szűrőfájlban (pl. xml/device_filter.xml) kell elhelyezni.

 

Microchip10 web

10. programrészlet: Egy alkalmazás automatikus indítása, ha egy specifikált készülék kapcsolódik az USB-portra USB Host-üzemmódban

 

Azokról a készülékekről, amelyek az USB-portra csatlakoztatás esetén egy alkalmazás indítását okozzák, a device_filter.xml fájl tartalmaz információkat. Ez lehet egy gyártóazonosítóból (Vendor ID – VID) és egy termékazonosítóból (Product ID – PID) álló adatpár, vagy meghatározza az osztályból (class), alosztályból (subclass) és protokollból (protocol) álló adathármas is (11. programrészlet).

 

Microchip11 web

11. programrészlet: Szűrő létrehozása egy készülék számára ahhoz, hogy USB Host-üzemmódban csatlakoztatva automatikusan elindítsa a hozzá társított alkalmazást


Azoknak az alkalmazásfejlesztőknek, akik nem egyetlen készülékre kívánnak specifikus automatikus indítást létrehozni, lehetőségük van arra is, hogy nem minden paramétert adjanak meg a paraméterlistában. Ha például a termékazonosító (PID) hiányzik, minden olyan készülék elindíthatja az alkalmazás indítását, amelynek a gyártóazonosítója (VID) egyezik.  

 

(Folytatjuk!)

 


[1]A „handler” kifejezést (a cikkben előforduló más kifejezésekkel együtt) az egyértelműség megtartása érdekében nem fordítjuk le, amennyiben a szöveg a megfelelő magyarázatot is tartalmazza. A „szó szerinti” fordítás félrevezető, a „körülírás” körülményesen olvasható, és egyikük sem felel meg a magyar szaknyelvben jobb híján alkalmazott szokásnak, amely ezeket a kifejezéseket „szakmai jövevényszónak” tekinti – A ford. megj.

 

[2]Fontos tudni, hogy az „életciklus” elnevezés ebben a szövegkörnyezetben mást jelent, mint amit megszoktunk. Életcikluson rendszerint azt érjük, ami egy termékkel történik az ötlet megjelenésétől a termék- és gyártásfejlesztésen, a módosításokon át egészen a „kivezetésig”. Itt azonban úgy értelmezzük, hogy egy alkalmazás futásának különböző fázisaiban értelemszerűen változik a gép (az alkalmazás) „viselkedése”, az a mód, ahogy a kezelői felületről vagy a kommunikációs csatornák felől érkező beavatkozásokra reagál. – A ford megj.

 

Szerző: David Flowers – Microchip Technology

 

www.microchip.com

 Még több Microchip Technology

 

Címkék: android