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 — 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.
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.
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.
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.
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.
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:
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:
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.
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.
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.
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.
A Kotlin lehetővé teszi a CoroutineScope megvalósításának delegálását a by kulcsszóval:
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 — egy CoroutineScope singleton a teljes alkalmazás számára. Használata éles kódban hivatalosan nem ajánlott.
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.
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.
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ő | coroutineScope | supervisorScope |
|---|---|---|
| Viselkedés hiba esetén | Kivétel a gyermek korutinban megszakítja az összes többit | Kivétel a gyermek korutinban NEM szakítja meg a többit |
| Hibaterjedés | Igen, az első kivétel kifelé terjed | Igen, az első kivétel kifelé terjed |
| Alapértelmezett Job | Job() — a gyermekek a szülőhöz kötődnek | SupervisorJob() — a gyermekek nem függnek egymástól |
| Tipikus használati eset | Atomi művelet több lépésből | Független párhuzamos feladatok (UI betöltések) |
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.
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.
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.
Tekintsük át a leggyakoribb fejlesztői hibákat a CoroutineScope Kotlinban történő használatakor.
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.
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.
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.
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
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.
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.
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.
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.
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ó
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