CoroutineScope — mi ez, élettartam és működés a korutinokban

Szerző: IT Sectr Megjelenés: 2026-06-22 Olvasási idő: 10 perc

CoroutineScope — egy Kotlin interfész, amely meghatározza a korutin élettartamát és kontextust biztosít új korutinok indításához. A Kotlin dokumentáció, 2025 szerint minden CoroutineScope példány tartalmaz egy CoroutineContext-et és kezeli a benne elindított összes korutint. Amikor a scope befejeződik (cancel), az összes gyermek korutin automatikusan megszakításra kerül, megelőzve a memóriaszivárgást.

Főbb pontok

  • CoroutineScope — interfész egyetlen CoroutineContext mezővel, amely meghatározza a korutinok életciklusát
  • Job — a megszakításért felelős kontextuselem: a scope megszakítása megszakítja az összes gyermek korutint
  • Strukturált konkurencia — elv, amely szerint a gyermek korutinok a szülő scope-hoz vannak kötve
  • GlobalScope — scope a teljes alkalmazáshoz, nem ajánlott a szivárgás kockázata miatt
  • supervisorScope — speciális scope, amelyben egy gyermek korutin megszakítása nem szakítja meg a többit

Mi az a CoroutineScope Kotlinban?

CoroutineScope — egy alapvető interfész a kotlinx.coroutines könyvtárból, amely tartályként szolgál a korutinok számára. Meghatározza a korutinok életbeli határait: amikor a scope véget ér, az összes benne lévő korutin automatikusan megszakításra kerül.

kotlin
public interface CoroutineScope {
    public val coroutineContext: CoroutineContext
}

Az interfész csak egy mezőt tartalmaz — coroutineContext. Ezen keresztül a scope diszpácser (Dispatcher), feladat (Job), kivételkezelés és egyéb kontextuselemeket biztosít az összes benne elindított korutin számára.

Szerep a kotlinx.coroutines könyvtárban

A korutinindító összes függvény — launch, async, runBlocking — kiterjesztési függvény a CoroutineScope-on. Ez azt jelenti, hogy csak scope objektum jelenlétében hívhatók meg. Az ilyen dizájn garantálja, hogy minden korutinnak egyértelműen meghatározott szülője és életciklusa van.

Hol alkalmazzák a CoroutineScope-ot

Androidban minden architektúrális komponensnek saját scope-ja van: viewModelScope a ViewModel számára, lifecycleScope az Activity/Fragment számára. Szerveralkalmazásokban a scope köthető egy HTTP kéréshez vagy egy adatbázis kapcsolati készlethez.

Hogyan működik a CoroutineScope: Job és strukturált konkurencia

A CoroutineScope belső felépítésének megértéséhez ismerni kell a Job koncepcióját és a strukturált konkurencia elvét.

Job — a korutin feladata

Minden korutin induláskor egy Job objektumot ad vissza (vagy async esetén Deferred). A Job egy meghatározott életciklusú feladatot képvisel: New, Active, Completing, Completed, Cancelling, Cancelled. A Job objektumok faszerkezetet alkotnak:

  • Szülő Job — a scope, amelyben a korutin elindult
  • Gyermek Job — minden launch/async útján elindított korutin
  • Szülő megszakítása → az összes gyermek megszakítása
  • Kivétel a gyermekben → a szülő megszakítása (kivéve supervisorScope)

A strukturált konkurencia elve

Strukturált konkurencia — a Kotlin Coroutines kulcsfontosságú architektúrális elve, amely szerint a korutin élettartama a scope élettartamához van kötve. Ez ellentétben áll a „fire-and-forget” modellel, ahol a korutin a scope befejeződése után is életben marad. A strukturált konkurencia előnyei:

  • Kiszámítható életciklus — amikor a scope véget ér, az összes korutin garantáltan leáll
  • Automatikus hibakezelés — a kivétel bármely gyermek korutinban elterjed a scope-ra
  • Nincs szivárgás — egyetlen korutin sem marad aktív a scope befejeződése után
  • Világos hierarchia — a kód tükrözi a párhuzamos műveletek logikai szerkezetét

A CoroutineScope életciklusa

Amikor a scope.cancel() meghívásra kerül, a scope Job-ja Cancelled állapotba kerül, ami rekurzívan megszakítja az összes gyermek Job-ot. A megszakítás után a scope csak új CoroutineScope példány létrehozásával használható újra.

CoroutineScope létrehozása és konfigurálása

A CoroutineScope létrehozható gyári függvénnyel vagy az interfész osztályban történő megvalósításával. Tekintsük át mindkét megközelítést.

CoroutineScope() gyári függvény

kotlin
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())

scope.launch {
    println("Futtatás itt: ${Thread.currentThread().name}")
}

A gyári függvény elfogadja a CoroutineContext-et és létrehoz egy scope-ot a megadott kontextussal. A példában Dispatchers.Default van használva CPU-intenzív feladatokhoz és SupervisorJob, amely elkülöníti a kivételeket a gyermek korutinok között.

Interfész megvalósítása kompozícióval

kotlin
class MyRepository {
    private val scope = CoroutineScope(Dispatchers.IO + Job())

    suspend fun fetchData(): Data = scope.async {
        api.getData()
    }.await()

    fun cleanup() {
        scope.cancel()
    }
}

A scope-ot osztálymezőként tároljuk és manuálisan meghívjuk a cleanup-ot a megszakításához. Ez alkalmas a kezelt életciklusú komponensek számára — például adattárak vagy menedzserek számára.

Megvalósítás delegálással

A Kotlin lehetővé teszi a CoroutineScope megvalósításának delegálását a by kulcsszóval:

kotlin
class DataLoader : CoroutineScope by CoroutineScope(Dispatchers.IO) {
    fun load() {
        launch {
            // korutin a DataLoader scope-ban fut
        }
    }
}

Ez a megközelítés akkor kényelmes, amikor az osztály maga is scope és korutinindító módszereket kíván biztosítani. Azonban legyen óvatos: az osztály örökli a CoroutineScope összes módszerét, beleértve a cancel-t is, ami megsértheti az enkapszulációt.

GlobalScope vs egyéni CoroutineScope

GlobalScope — egy CoroutineScope singleton a teljes alkalmazás számára. Használata éles kódban hivatalosan nem ajánlott.

A GlobalScope problémái

  • Strukturált konkurencia hiánya — a GlobalScope korutinjai nem kötődnek a komponens életciklusához
  • Memóriaszivárgás — a korutin tovább futhat az Activity/Fragment bezárása után
  • Nehéz tesztelés — a GlobalScope nem cserélhető le tesztekben
  • Ellenőrizetlen erőforrás-felhasználás — sok korutin tovább dolgozhat a vártnál

Mikor indokolt a GlobalScope

A JetBrains csak ritka forgatókönyvekben engedélyezi a GlobalScope-ot: alkalmazásszintű háttérfolyamatok, amelyeknek az összes Activity bezárása után is életben kell maradniuk (például adatszinkronizáció, analitika). De még ezekben az esetekben is jobb saját scope-ot létrehozni a CoroutineScope(SupervisorJob()) segítségével.

Ajánlás

Mindig használjon egyéni CoroutineScope-ot explicit életciklus-kezeléssel. Androidban ezek a viewModelScope és a lifecycleScope. Szerveralkalmazásokban hozzon létre scope-ot minden kéréshez vagy kapcsolati készlethez.

coroutineScope vs supervisorScope: mi a különbség

Mindkét függvény suspend függvény, amelyek ideiglenes scope-ot hoznak létre párhuzamos feladatokhoz, de a kivételek kezelésében alapvetően különböznek.

JellemzőcoroutineScopesupervisorScope
Viselkedés hiba eseténKivétel a gyermek korutinban megszakítja az összes többitKivétel a gyermek korutinban NEM szakítja meg a többit
HibaterjedésIgen, az első kivétel kifelé terjedIgen, az első kivétel kifelé terjed
Alapértelmezett JobJob() — a gyermekek a szülőhöz kötődnekSupervisorJob() — a gyermekek nem függnek egymástól
Tipikus használati esetAtomi művelet több lépésbőlFüggetlen párhuzamos feladatok (UI betöltések)

Mikor válassza a coroutineScope-ot

Használja a coroutineScope-ot, amikor több párhuzamos művelet egyetlen atomi műveletet alkot. Például adatok betöltése három szerverről: ha az egyik kérés meghiúsul, a többinek nincs értelme.

kotlin
suspend fun loadProductPage(): ProductPage = coroutineScope {
    val product = async { api.getProduct() }
    val reviews = async { api.getReviews() }
    ProductPage(product.await(), reviews.await())
}

Ha a getProduct vagy a getReviews kivételt dob — mindkét korutin megszakad és a kivétel a hívó kódhoz terjed.

Mikor válassza a supervisorScope-ot

Használja a supervisorScope-ot, amikor a párhuzamos műveletek nem függnek egymástól. Például profiladatok betöltése több független szakaszban: ha az ajánlási szakasz meghiúsul, a profil fejlécének és a barátlista megjelenítésének továbbra is működnie kell.

Gyakori hibák a CoroutineScope használatakor

Tekintsük át a leggyakoribb fejlesztői hibákat a CoroutineScope Kotlinban történő használatakor.

Hiba 1: Elfelejtette megszakítani a scope-ot

A korutin szivárgásának leggyakoribb forgatókönyve — scope létrehozása a cancel meghívása nélkül a komponens befejeződésekor. Ha a scope nem kerül megszakításra, a korutinok tovább futnak, referenciákat tartva az objektumokra. Androidban használja a viewModelScope-ot vagy a lifecycleScope-ot, amelyek automatikusan megszakadnak.

Hiba 2: GlobalScope használata Activity-ben vagy Fragment-ben

A GlobalScope figyelmen kívül hagyja az Android komponensek életciklusát. Az Activity bezárása után GlobalScope-ban indított korutin tovább fut és megpróbálja frissíteni az UI-t — ami crash-hez vezet. Mindig használja a lifecycleScope-ot az UI komponensekhez.

Hiba 3: Megszakított scope újrafelhasználása

A cancel() meghívása után a scope nem használható újra — a benne lévő összes korutin már befejeződött. Hozzon létre új CoroutineScope példányt a gyári függvény segítségével. A Job() nem támogatja az újraaktiválást.

Hiba 4: A CoroutineScope interfész helytelen delegálása

A by kulcsszóval történő delegáláskor az osztály egy nyilvános cancel() metódust kap, amely bárhonnan meghívható, megsértve az enkapszulációt. Tárolja a scope-ot privát mezőként, ne delegálja az interfészt.

Gyakran Ismételt Kérdések

Miben különbözik a CoroutineScope és a CoroutineContext?

CoroutineScope — egy interfész, amely birtokolja a CoroutineContext-et és felelős a korutinok életciklusáért. CoroutineContext — elemek halmaza (diszpácser, job, hibakezelés), amely meghatározza, hogy a korutin „hogyan” hajtódik végre. Az egyik különbség: a scope korutinokat hoz létre, a context kezeli a viselkedésüket.

Létrehozható CoroutineScope SupervisorJob-jal?

Igen, ez egy szabvány minta: CoroutineScope(Dispatchers.IO + SupervisorJob()). A SupervisorJob megakadályozza a gyermek korutinok lépcsőzetes megszakítását, ha az egyikben kivétel történik. Ez hasznos független párhuzamos feladatokhoz, ahol az egyik hibája nem állíthatja le a többit.

Hány korutint tartalmazhat egy CoroutineScope?

Nincs korlátozás a korutinok számára egy scope-ban — azokat csak a rendelkezésre álló memória és a diszpácser beállításai korlátozzák. A gyakorlati határ általában több ezer aktív korutin egyetlen scope-ban. A nagy számú korutin azonban architekturális problémákra utalhat.

Hogyan teszteljem a kódot CoroutineScope-pal?

A helyes módszer a scope átadása az osztálynak a konstruktoron keresztül, vagy a runBlockingTest / runTest használata a kotlinx-coroutines-test könyvtárból. Tesztekben a scope-ot kicserélheti TestCoroutineDispatcher-re és manuálisan irányíthatja a korutinok végrehajtását.

Lehet egy korutinnak saját scope-ja?

Nem, a scope egy külső tartály a korutin számára. Maga a korutin nem scope. A korutinen belül azonban létrehozható új scope a coroutineScope vagy a supervisorScope segítségével gyermek korutinok párhuzamos indításához.

Összefoglaló

  • CoroutineScope — interfész coroutineContext mezővel, amely meghatározza a benne elindított korutinok életciklusát
  • Strukturált konkurencia — a scope megszakítása automatikusan megszakítja az összes gyermek korutint, megelőzve a memóriaszivárgást
  • Job és SupervisorJob — két hibakezelési mód: lépcsőzetes megszakítás (Job) és elkülönített hibák (SupervisorJob)
  • GlobalScope — nem ajánlott éles célra az életciklushoz való kötés hiánya miatt
  • coroutineScope vs supervisorScope — atomi párhuzamos műveletek vs független párhuzamos feladatok
  • viewModelScope és lifecycleScope — kész scope-ok Androidhoz, automatikusan megszakadnak a komponens befejeződésekor
  • Gyári függvény — a scope létrehozásának előnyös módja CoroutineContext + explicit cancel hívás segítségével

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.

Projekt megbeszélése

Olvassa el is