A Coroutines (korutinok) könnyű Kotlin-szálak aszinkron programozáshoz, amelyek a kotlinx.coroutines könyvtáron keresztül érhetők el. A JetBrains Kotlin Documentation, 2026 szerint a Coroutines lehetővé teszi a függvény végrehajtásának felfüggesztését a szál blokkolása nélkül, ellentétben a hagyományos Thread-ekkel. A korutinok korlátozott szálkészleten futnak, ami ezerszer könnyebbé teszi őket a natív szálaknál. A Kotlin Coroutines teljes mértékben integrált az Android Jetpack, Retrofit, Room és más népszerű Android-ökoszisztéma könyvtárakkal.
Főbb pontok
Coroutines (korutinok) egy aszinkron programozási mechanizmus Kotlinban, amely a kotlinx.coroutines könyvtárban van implementálva. Az operációs rendszer szálaitól eltérően a korutinok nincsenek egy adott szálhoz kötve: felfüggeszthetők az egyik szálon és folytathatók egy másikon. Egyetlen szál több ezer korutint hajthat végre, minimális többletköltséggel váltva közöttük.
A korutinok a Kotlin 1.3-ban (2018) jelentek meg kísérleti funkcióként, és a Kotlin 1.5-ben (2021) váltak stabillá. A Coroutines a callback hell problémáját az async/await-hez hasonlóan oldja meg, de gazdagabb API-t kínál: csatornák (Channel), Flow, kivételkezelés a Job hierarchiában és közvetlen integráció az Android Lifecycle-lel.
A JetBrains (2025) szerint minden korutin körülbelül 100 bájt memóriát fogyaszt szemben a natív szál 1+ MB-jával. Ez lehetővé teszi több millió korutin futtatását egyetlen alkalmazásban OutOfMemoryError kockázata nélkül. Éppen a korutinok könnyűsége teszi őket az aszinkronitás előnyben részesített eszközévé Androidon.
Minden Kotlin-korutin Continuation Passing Style (CPS) segítségével állapotgéppé fordul. A fordító egy rejtett Continuation paramétert ad minden suspend függvényhez. A Continuation tartalmazza a folytatási pontot és az összes lokális változót. Amikor a korutin felfüggesztődik, a runtime elmenti a Continuation-t, és amikor folytatódik, visszaállítja azt a Dispatcher készlet bármely elérhető szálán.
suspend — a Kotlin kulcsszava, amely felfüggeszthetőként jelöli meg a függvényt. Egy ilyen függvény csak másik suspend függvényből vagy korutinból hívható meg. Egy suspend függvényen belül más suspend függvények tetszőleges sorrendben hívhatók, és minden hívási pont potenciális felfüggesztési pont.
A mechanika egyszerű: amikor egy suspend függvény meghív egy másik suspend függvényt, felfüggesztődik abban a pontban, felszabadítva a szálat. A meghívott függvény befejezése után a runtime az elmentett helyről folytatja a végrehajtást. Ezt cooperative cancellation-nek hívják — egyetlen szál sem blokkolódik.
Fontos: a suspend függvény alapértelmezetten nem aszinkron. A végrehajtás sorrendje szekvenciális marad, ha nem használnak launch vagy async függvényt. A suspend csak azt teszi lehetővé, hogy a függvény felfüggeszthető legyen a szál blokkolása nélkül, és a korutin kontextus részét képezze. A Continuation Passing Style egy olyan fordítási modell, amelyben minden suspend függvény kap egy rejtett Continuation callback-et, és a fordító egy állapotgépet generál a felfüggesztések és folytatások kezelésére.
CoroutineScope egy kontextus, amely meghatározza a korutinok életciklusát. Minden korutint egy scopen belül kell elindítani. Amikor a scope megszakításra kerül (pl. egy Activity befejezésekor), az összes gyermek korutin automatikusan megszakításra kerül. Ez megakadályozza a háttérfeladatok szivárgását. Az Android Jetpack kész scope-okat biztosít minden komponenshez: viewModelScope a ViewModel-hez és lifecycleScope az Activity-hez és Fragment-hez, amelyek automatikusan megszakadnak a megfelelő komponens megsemmisülésekor.
Structured Concurrency — az az elv, amely garantálja, hogy egy korutin nem fejeződik be addig, amíg az összes gyermek korutinja be nem fejeződött. A Job hierarchia egy fát alkot: a gyökér korutin létrehoz egy parent job-ot, a gyermekek child job-okat hoznak létre. A parent job megszakítása az összes gyermekre terjed. A Structured Concurrency az alapvető különbség a korutinok és a szálak között.
| Scope | Hol használják | Megszakítás |
|---|---|---|
| GlobalScope | Csak démonfeladatokhoz | Nem szakad meg automatikusan |
| viewModelScope | Android ViewModel | ViewModel tisztításakor |
| lifecycleScope | Android Activity/Fragment | Lifecycle megsemmisülésekor |
| coroutineScope | Suspend függvényen belül | A parent job megszakításakor |
A szokásos Job egy gyermek korutin hibája esetén megszakítja az összes testvért. A SupervisorJob kivétel: az egyik gyermek korutin hibája nem befolyásolja a többit. Ez akkor fontos, amikor több független feladat fut párhuzamosan, és az egyik meghiúsulhat anélkül, hogy a többit meg kellene szakítani.
Dispatchers határozza meg, hogy a korutinok mely szálakon fussanak. Dispatchers.Main — az Android fő UI-szála. Dispatchers.IO — készlet blokkoló műveletekhez (hálózat, lemez). Dispatchers.Default — CPU-intenzív feladatokhoz. Dispatchers.Unconfined — az aktuális szálon indul, de nem garantálja, hogy ott is marad. A megfelelő Dispatcher kiválasztása kritikus a teljesítmény szempontjából: egy IO-feladat a Default-on blokkolja a készletet a számításokhoz, míg egy CPU-feladat az IO-n felesleges szálakat hoz létre.
withContext — a Dispatcher váltására szolgáló függvény a korutinon belül. Például egy JSON-t elemző suspend függvény átválthat Dispatchers.Default-re a számítás során, és visszatérhet Dispatchers.Main-re a UI frissítéséhez. A withContext a leggyakrabban használt építő az Android-fejlesztésben.
launch — elindít egy korutint, visszaad egy Job-ot, nem ad vissza eredményt (fire-and-forget). async — elindít egy korutint, visszaad egy Deferred-et, amelyből az eredmény await-en keresztül érhető el. runBlocking — blokkolja az aktuális szálat a korutin végrehajtásához (csak tesztekhez és main függvényekhez). Az építő kiválasztása a forgatókönyvtől függ: a launch eseményekhez és frissítésekhez, az async eredménnyel járó feladatokhoz, a runBlocking csak tesztekhez vagy belépési pontokhoz alkalmas.
Vizsgáljunk meg három gyakorlati forgatókönyvet: alap korutin launch-al, párhuzamos hívás async-kal és hibakezelés SupervisorJob-bal.
viewModelScope.launch elindít egy korutint a ViewModel kontextusában. A ViewModel tisztításakor a korutin automatikusan megszakad.
class ProfileViewModel : ViewModel() {
fun loadUser() {
viewModelScope.launch(Dispatchers.IO) {
val user = api.fetchUser()
withContext(Dispatchers.Main) {
showUser(user)
}
}
}
}
coroutineScope async-kal három kérést indít párhuzamosan. Az eredmények a .await() segítségével gyűjthetők össze. Ha bármelyik kérés meghiúsul, az összes megszakad.
suspend fun loadDashboard(): Dashboard = coroutineScope {
val user = async { api.fetchUser() }
val posts = async { api.fetchPosts() }
val stats = async { api.fetchStats() }
Dashboard(user.await(), posts.await(), stats.await())
}
SupervisorJob lehetővé teszi, hogy minden korutin függetlenül fejeződjön be. Az egyik kérés hibája nem szakítja meg a többit.
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
try { api.fetchPosts() } catch (e: Exception) { log(e) }
}
A szálak (Thread) az operációs rendszer primitívjei. Minden szálnak saját verme (~1 MB) van, és létrehozásához és váltásához rendszerhívás szükséges. A korutinok nyelvi primitívek, amelyek nem kötődnek az OS-hez. A Continuation-t használják az állapot mentésére, és futásidejű szinten váltanak rendszerhívások nélkül.
A Google (2025) szerint a korutinok szálak helyetti használata 90–95%-kal csökkenti a memóriafogyasztást a háttérfeladatokhoz Android-alkalmazásokban. Az összes modern Android-könyvtár (Retrofit, Room, WorkManager) beépített támogatással rendelkezik a korutinokhoz suspend függvényeken keresztül. A Ktor (a JetBrains HTTP kliens keretrendszere) szintén teljes egészében korutinokra épül, minden kéréshez suspend-függvényeket biztosítva callback API nélkül. A Room támogatja a korutinokat a DAO-ban lévő suspend-függvényeken keresztül, lehetővé téve az adatbázis-lekérdezések végrehajtását a fő szál blokkolása nélkül.
A szálak továbbra is szükségesek a natív kódhoz JNI-n keresztül, a blokkoló CPU-intenzív hívásokhoz időkorlát nélkül (videó renderelés, szimulációk) és a C könyvtárakkal való integrációhoz. Minden másra — korutinok.
Gyakran Ismételt Kérdések
Korutin — egy felfüggeszthető munkaegység, amely egy meglévő szálon fut. A szál egy rendszererőforrás saját veremmel. A korutinok ezerszer könnyebbek a szálaknál, és nem blokkolják az erőforrásokat felfüggesztéskor.
Dispatchers.IO blokkoló I/O műveletekhez (hálózat, fájlok) való, és szükség esetén új szálakat hozhat létre. Dispatchers.Default fix méretű készlettel rendelkezik (CPU-magok száma) CPU-intenzív számításokhoz.
Job.cancel() megszakítja a korutint és az összes gyermekét. A megszakítás ellenőrzéséhez a korutinon belül használja a ensureActive() függvényt — CancellationException-t dob, ha a korutin megszakításra került.
Igen — a kotlinx-coroutines-rx3 könyvtáron keresztül. Az awaitSingle, awaitFirst és más függvényeket biztosít az Observable/Single suspend függvényekké alakításához és vissza a flowable segítségével.
Flow — egy hideg aszinkron adatfolyam, az RxJava Observable megfelelője korutinokhoz. A Flow szekvenciálisan bocsát ki értékeket, és kivétellel vagy sikerrel végződik. Támogatja a map, filter, catch és más operátorokat.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is