Aszinkronitás, API kommunikáció és perzisztencia
Ez az anyag segít átlátni a mobilfejlesztés egyik legkritikusabb részét: hogyan kommunikáljunk a külvilággal és hogyan tároljuk az adatokat anélkül, hogy a felhasználó agyára mennénk egy lefagyott gombbal vagy egy üres fehér képernyővel.
Az aszinkronitás elmélete: Miért ne fagyasszuk le a világot?
A "Szent" UI Thread
Minden mobilalkalmazás lelke a Main (vagy UI) Thread. Ez a szál felelős mindenért, amit a felhasználó lát: a gombok rajzolásáért, az animációkért és az érintések feldolgozásáért.
- Az aranyszabály: Soha ne végezz rajta nehéz műveletet (hálózati hívás, fájlba írás)!
- A következmény: Ha a UI szál 5 másodpercnél tovább várakozik, jön az ANR (Application Not Responding) párbeszédablak, a felhasználó pedig törli az appodat.
Párhuzamosság vs. Egyidejűség (Concurrency vs. Parallelism)
Sokan keverik, de fontos különbség:
- Concurrency: Több feladattal foglalkozunk egyszerre (pl. elindítunk egy letöltést, de közben hagyjuk a felhasználót görgetni). Nem biztos, hogy egyszerre is futnak, csak "váltogatunk" köztük.
- Parallelism: Valóban, fizikailag egyszerre futnak a műveletek (többmagos processzorokon).
A sötét oldal: Race Condition és Deadlock
Amikor több szálon dolgozunk, jönnek a bajok:
- Race Condition: Erre hozok egy példát: Ketten álltok a MediaMarktban az utolsó leárazott Ályfon előtt. Mindketten egyszerre nyúltok érte. A helyzet: Ha nincs „szinkronizáció” (pl. egy eladó, aki megmondja, kié volt az első érintés), akkor elszakad a doboz, és egyikőtöknek sem lesz tévéje, vagy mindketten kifizetitek, de csak egyikőtök viszi haza. Programozásnál ez az, amikor két szál egyszerre akarja ugyanazt a változót átírni, és a végeredmény totális káosz lesz.
- Deadlock: "A vár B-re hogy nyomtasson, B vár A-ra hogy nyomtasson, én meg kidobtam a nyomtatót az ablakon, szóval sosem tudjuk meg a végeredményt"
Az aszinkronitás evolúciója
Régen Callback-eket használtunk (függvény a függvényben), ami elvezetett a Callback Hell-hez (olvashatatlan kód). Ezt váltották a Promise/Future objektumok, majd megérkezett a modern megváltás: az async/await. Ez lehetővé teszi, hogy aszinkron kódot úgy írjunk, mintha szekvenciális (egymás utáni) lenne, így emberi ésszel is felfogható marad.
Networking: Beszélgessünk a szerverrel
A "Három Állapot" szabálya
Bármilyen API hívást végzel, a kódodnak (és a UI-nak) kötelező kezelnie ezt a hármast:
- Loading: Pörögjön a homokóra/shimmer, hogy a felhasználó tudja: dolgozunk.
- Success: Megérkezett az adat, jelenítsük meg.
- Error: Hiba történt (nincs net, 500-as szerverhiba). Ne csak egy üres képernyő legyen, mondjuk meg mi a baj! Légyszi ne legyünk olyanok, hogy "Valami hiba történt".
Hibakezelés: Exponential Backoff
Ha egy hívás sikertelen, nem bombázzuk a szervert másodpercenként. Használjunk exponenciális várakozást: várj 1 másodpercet, aztán 2-t, 4-et, 8-at... és adj hozzá egy kis véletlenszerűséget (jitter), hogy ne minden kliens egyszerre támadja be a szervert a javulás után.
Reaktív folyamatok (Streams)
Néha nem egyetlen adat kell, hanem adatok folyama (pl. tőzsdei árfolyamok). Erre használjuk a Reactive Streams-et (Androidon Flow, iOS-en Combine, Flutterben Stream). Itt operátorokkal (map, filter) alakíthatjuk az adatfolyamot útközben.
Perzisztencia: Hogy ne felejtsünk el semmit
Offline-First gondolkodás
Egy profi app nem omlik össze, ha éppen a metró alagútjában nyomogatjuk. Az adatokat elmentjük helyben, és ha van net, szinkronizálunk.
- ACID: A tranzakciók alapköve. Garantálja, hogy egy mentés vagy teljesen sikerül, vagy semennyire (nincs félkész adat).
- CAP tétel: Egy elosztott rendszerben csak kettő választható: Consistency (Konzisztencia), Availability (Rendelkezésre állás), Partition tolerance (Hálózatkimaradás-tűrés). - Ez elsősorban akkor fontos, ha hálózati hiba van. Bővebben erről itt olvashatsz.
Tárolási típusok
- Key-Value: Egyszerű beállításokhoz (pl. "Dark Mode: ON").
- Relációs (SQLite): Strukturált adatokhoz (pl. felhasználók és a hozzájuk tartozó posztok).
- Document-based: Rugalmas, sémamentes tárolás. (pl: MongoDB)
Fontos minták (Patterns)
- Repository Pattern: Az app "Single Source of Truth" (egyetlen igazságforrás) pontja. A UI nem tudja, hogy az adat a netről jön vagy a helyi adatbázisból – a Repository dönti el.
- Optimistic Update: "Légy optimista!" Ha a felhasználó lájkol egy posztot, azonnal színezd ki a szívecskét, és csak a háttérben küldd el az API-nak. Ha hiba van, vond vissza (rollback).
Technológiai Gyorsnézet
| Platform | Aszinkronitás | Networking | Adatbázis |
|---|---|---|---|
| Android | Coroutines, Flow | Retrofit, OkHttp | Room, DataStore |
| iOS | async/await, Tasks | URLSession, Alamofire | SwiftData, CoreData |
| Flutter | Future, Stream | Dio, http | Hive, Isar, Drift |
AI Promptok
"Generálj egy [PLATFORM: Android/iOS/Flutter] kódot egy REST API híváshoz, amely kezeli a Loading, Success és Error állapotokat egy Sealed Class/Enum segítségével. Implementálj egy egyszerű Retry logikát is!" "Írj egy Repository osztályt, ami megvalósítja a Cache-Aside stratégiát: először a helyi adatbázisban (pl. Room/SwiftData) keresi az adatot, ha nincs ott, letölti a hálózatról és elmenti a cache-be." "Magyarázd el példakóddal, hogyan tudok Race Condition-t elkerülni, ha egy felhasználó túl gyorsan kattint egymás után egy 'Küldés' gombra [PLATFORM] környezetben."
Irodalomjegyzék
- Android Developers: Kotlin Coroutines guide
- Swift.org: Concurrency in Swift
- Flutter.dev: Asynchronous programming
- Offline-first elvek: Offline Guide by Google