CoroutineScope — ano ito, saklaw ng buhay at paggana sa coroutine

May-akda: IT Sectr Nai-publish: 2026-06-22 Oras ng pagbabasa: 10 min

CoroutineScope — ay isang interface ng Kotlin na tumutukoy sa saklaw ng buhay ng coroutine at nagbibigay ng konteksto para sa paglulunsad ng mga bagong coroutine. Ayon sa dokumentasyon ng Kotlin, 2025, bawat instance ng CoroutineScope ay naglalaman ng CoroutineContext at namamahala sa lahat ng coroutine na inilunsad dito. Kapag natapos ang scope (cancel), lahat ng coroutine na anak ay awtomatikong kinansela, na pumipigil sa pagtagas ng memorya.

Mga Pangunahing Punto

  • CoroutineScope — interface na may iisang field na CoroutineContext, na tumutukoy sa siklo ng buhay ng mga coroutine
  • Job — elemento ng konteksto na responsable para sa pagkansela: ang pagkansela ng scope ay kinakansela ang lahat ng coroutine na anak
  • Konkurensiyang struktural — prinsipyo kung saan ang mga coroutine na anak ay nakatali sa scope ng magulang
  • GlobalScope — scope para sa buong application, hindi inirerekomenda dahil sa panganib ng pagtagas
  • supervisorScope — espesyal na scope kung saan ang pagkansela ng isang coroutine na anak ay hindi kinakansela ang iba

Ano ang CoroutineScope sa Kotlin?

CoroutineScope — ay isang pangunahing interface mula sa library ng kotlinx.coroutines na nagsisilbing lalagyan para sa mga coroutine. Tinutukoy nito ang mga hangganan ng buhay ng mga coroutine: kapag natapos ang scope, lahat ng coroutine sa loob nito ay awtomatikong kinakansela.

kotlin
public interface CoroutineScope {
    public val coroutineContext: CoroutineContext
}

Ang interface ay naglalaman lamang ng isang field — coroutineContext. Sa pamamagitan nito, ang scope ay nagbibigay ng dispatcher (Dispatcher), gawain (Job), pangangasiwa ng exception, at iba pang elemento ng konteksto para sa lahat ng coroutine na inilunsad dito.

Papel sa library ng kotlinx.coroutines

Lahat ng function ng paglulunsad ng coroutine — launch, async, runBlocking — ay extension function sa CoroutineScope. Nangangahulugan ito na maaari lamang silang tawagin kung mayroong object ng scope. Ang ganitong disenyo ay ginagarantiyahan na ang bawat coroutine ay may malinaw na tinukoy na magulang at siklo ng buhay.

Saan inilalapat ang CoroutineScope

Sa Android, bawat bahagi ng arkitektura ay may sariling scope: viewModelScope para sa ViewModel, lifecycleScope para sa Activity/Fragment. Sa mga server application, ang scope ay maaaring itali sa isang HTTP request o sa isang pool ng mga koneksyon sa database.

Paano Gumagana ang CoroutineScope: Job at Konkurensiyang Struktural

Ang pag-unawa sa panloob na istraktura ng CoroutineScope ay nangangailangan ng pamilyaridad sa konsepto ng Job at prinsipyo ng konkurensiyang struktural.

Job — Gawain ng Coroutine

Bawat coroutine sa paglulunsad ay nagbabalik ng Job object (o Deferred para sa async). Job ay kumakatawan sa isang gawain na may tinukoy na siklo ng buhay: New, Active, Completing, Completed, Cancelling, Cancelled. Ang mga Job object ay bumubuo ng istraktura ng puno:

  • Job ng Magulang — scope kung saan inilunsad ang coroutine
  • Job na Anak — bawat coroutine na inilunsad sa pamamagitan ng launch/async
  • Pagkansela ng magulang → pagkansela ng lahat ng anak
  • Exception sa anak → pagkansela ng magulang (maliban sa supervisorScope)

Prinsipyo ng Konkurensiyang Struktural

Konkurensiyang struktural — pangunahing prinsipyo ng arkitektura ng Kotlin Coroutines, kung saan ang buhay ng coroutine ay nakatali sa buhay ng scope nito. Ito ay kaibahan sa modelo ng “fire-and-forget”, kung saan ang coroutine ay patuloy na nabubuhay pagkatapos ng pagtatapos ng scope. Mga bentahe ng konkurensiyang struktural:

  • Mahuhulaan na siklo ng buhay — kapag natapos ang scope, lahat ng coroutine ay garantisadong hihinto
  • Awtomatikong pangangasiwa ng error — exception sa anumang coroutine na anak ay kumakalat sa scope
  • Walang pagtagas — walang coroutine na nananatiling aktibo pagkatapos ng pagtatapos ng scope
  • Malinaw na hierarchy — ang code ay sumasalamin sa lohikal na istraktura ng mga parallel na operasyon

Siklo ng Buhay ng CoroutineScope

Kapag tinawag ang scope.cancel(), ang Job ng scope ay pumunta sa status na Cancelled, na kung saan ay recursively kinakansela ang lahat ng Job na anak. Pagkatapos ng pagkansela, ang scope ay maaari lamang magamit muli sa pamamagitan ng paglikha ng bagong instance ng CoroutineScope.

Paglikha at Pag-configure ng CoroutineScope

Ang CoroutineScope ay maaaring likhain sa pamamagitan ng factory function o sa pamamagitan ng pagpapatupad ng interface sa iyong klase. Talakayin natin ang parehong approach.

Factory Function na CoroutineScope()

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

scope.launch {
    println("Tumatakbo sa ${Thread.currentThread().name}")
}

Ang factory function ay tumatanggap ng CoroutineContext at lumilikha ng scope na may tinukoy na konteksto. Sa halimbawa, ginamit ang Dispatchers.Default para sa mga gawaing CPU-intensive at SupervisorJob na nagbubukod ng mga exception sa pagitan ng mga coroutine na anak.

Pagpapatupad ng Interface sa pamamagitan ng Komposisyon

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

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

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

Itinatago namin ang scope bilang field ng klase at manu-manong tinatawagan ang cleanup para kanselahin ito. Ito ay angkop para sa mga bahagi na may pinamamahalaang siklo ng buhay — halimbawa, para sa mga repositoryo o manager.

Pagpapatupad sa pamamagitan ng Delegasyon

Pinapayagan ng Kotlin ang delegasyon ng pagpapatupad ng CoroutineScope sa pamamagitan ng keyword na by:

kotlin
class DataLoader : CoroutineScope by CoroutineScope(Dispatchers.IO) {
    fun load() {
        launch {
            // coroutine ay tumatakbo sa DataLoader scope
        }
    }
}

Ang approach na ito ay maginhawa kapag ang klase mismo ay isang scope at nais na magbigay ng mga pamamaraan ng paglulunsad ng coroutine. Gayunpaman, mag-ingat: minamana ng klase ang lahat ng pamamaraan ng CoroutineScope, kabilang ang cancel, na maaaring lumabag sa encapsulation.

GlobalScope vs Pasadyang CoroutineScope

GlobalScope — ay isang singleton ng CoroutineScope para sa buong application. Ang paggamit nito sa production code ay opisyal na hindi inirerekomenda.

Mga Problema ng GlobalScope

  • Kakulangan ng konkurensiyang struktural — ang mga coroutine sa GlobalScope ay hindi nakatali sa siklo ng buhay ng bahagi
  • Pagtagas ng memorya — ang coroutine ay maaaring magpatuloy sa pagtakbo pagkatapos isara ang Activity/Fragment
  • Mahirap na pagsubok — ang GlobalScope ay hindi mapapalitan sa mga pagsubok
  • Hindi kontroladong pagkonsumo ng mapagkukunan — maraming coroutine ang maaaring gumana nang mas matagal kaysa sa inaasahan

Kailan Nabibigyang-katwiran ang GlobalScope

Pinapahintulutan ng JetBrains ang GlobalScope lamang sa mga bihirang sitwasyon: mga proseso sa background sa antas ng application na dapat manatiling buhay kahit na matapos isara ang lahat ng Activity (halimbawa, pag-sync ng data, analytics). Ngunit kahit sa mga kasong ito, mas mainam na lumikha ng sariling scope gamit ang CoroutineScope(SupervisorJob()).

Rekomendasyon

Palaging gumamit ng pasadyang CoroutineScope na may tahasang pamamahala ng siklo ng buhay. Sa Android, ito ay viewModelScope at lifecycleScope. Sa mga server application, lumikha ng scope para sa bawat request o pool ng mga koneksyon.

coroutineScope vs supervisorScope: Ano ang Pagkakaiba

Parehong function ay suspend function na lumilikha ng pansamantalang scope para sa mga parallel na gawain, ngunit ang kanilang pag-uugali sa mga exception ay pangunahing naiiba.

KatangiancoroutineScopesupervisorScope
Pag-uugali sa errorException sa coroutine na anak ay kinakansela ang lahat ng iba paException sa coroutine na anak ay HINDI kinakansela ang iba
Pagkalat ng errorOo, ang unang exception ay kumakalat sa labasOo, ang unang exception ay kumakalat sa labas
Default na JobJob() — mga anak ay nakatali sa magulangSupervisorJob() — mga anak ay hindi nakadepende sa isa’t isa
Karaniwang use-caseAtomikong operasyon mula sa maraming hakbangIndependiyenteng parallel na gawain (mga UI load)

Kailan Pumili ng coroutineScope

Gamitin ang coroutineScope kapag maraming parallel na operasyon ang bumubuo ng isang atomikong operasyon. Halimbawa, pagkarga ng data mula sa tatlong server: kung ang isang request ay bumagsak, ang iba ay walang saysay.

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

Kung ang getProduct o getReviews ay naghagis ng exception — parehong coroutine ay kinansela, at ang exception ay kumakalat sa tumatawag na code.

Kailan Pumili ng supervisorScope

Gamitin ang supervisorScope kapag ang mga parallel na operasyon ay hindi nakadepende sa isa’t isa. Halimbawa, pagkarga ng data ng profile sa maraming independiyenteng seksyon: kung ang seksyon ng mga rekomendasyon ay bumagsak, ang header ng profile at listahan ng mga kaibigan ay dapat ipakita.

Mga Karaniwang Pagkakamali sa Paggamit ng CoroutineScope

Talakayin natin ang pinakakaraniwang pagkakamali ng mga developer sa paggamit ng CoroutineScope sa Kotlin.

Pagkakamali 1: Nakalimutang Kanselahin ang Scope

Ang pinakakaraniwang sitwasyon ng pagtagas ng coroutine — paglikha ng scope nang hindi tinatawagan ang cancel kapag natapos ang bahagi. Kung ang scope ay hindi nakansela, ang mga coroutine ay patuloy na tumatakbo, na may hawak na mga reference sa mga bagay. Sa Android, gamitin ang viewModelScope o lifecycleScope, na awtomatikong kinakansela.

Pagkakamali 2: Paggamit ng GlobalScope sa Activity o Fragment

Binabalewala ng GlobalScope ang siklo ng buhay ng mga bahagi ng Android. Ang coroutine na inilunsad sa GlobalScope pagkatapos isara ang Activity ay magpapatuloy sa pagtakbo at susubukan na i-update ang UI — na magdudulot ng crash. Palaging gamitin ang lifecycleScope para sa mga bahagi ng UI.

Pagkakamali 3: Muling Paggamit ng Nakanselang Scope

Pagkatapos tawagan ang cancel(), ang scope ay hindi maaaring magamit muli — lahat ng coroutine sa loob nito ay tapos na. Lumikha ng bagong instance ng CoroutineScope sa pamamagitan ng factory function. Job() ay hindi sumusuporta sa muling pag-activate.

Pagkakamali 4: Maling Delegasyon ng Interface ng CoroutineScope

Sa delegasyon sa pamamagitan ng by, ang klase ay nakakakuha ng pampublikong pamamaraan na cancel() na maaaring tawagan mula sa kahit saan, lumalabag sa encapsulation. Itago ang scope bilang pribadong field, huwag i-delegate ang interface.

Mga Madalas Itanong

Ano ang pagkakaiba ng CoroutineScope at CoroutineContext?

CoroutineScope — ay isang interface na nagmamay-ari ng CoroutineContext at responsable para sa siklo ng buhay ng mga coroutine. CoroutineContext — ay isang set ng mga elemento (dispatcher, job, pangangasiwa ng error) na tumutukoy “paano” isinasagawa ang coroutine. Isa sa mga pagkakaiba: scope lumilikha ng coroutine, context namamahala ng kanilang pag-uugali.

Maaari bang lumikha ng CoroutineScope gamit ang SupervisorJob?

Oo, ito ay isang karaniwang pattern: CoroutineScope(Dispatchers.IO + SupervisorJob()). Pinipigilan ng SupervisorJob ang cascading cancellation ng mga coroutine na anak kapag may exception sa isa sa kanila. Ito ay kapaki-pakinabang para sa mga independiyenteng parallel na gawain kung saan ang error sa isa ay hindi dapat huminto sa iba.

Ilang coroutine ang kayang taglayin ng CoroutineScope?

Walang mga limitasyon sa bilang ng mga coroutine sa isang scope — sila ay limitado lamang ng magagamit na memorya at mga setting ng dispatcher. Ang praktikal na limitasyon ay karaniwang libu-libong aktibong coroutine sa isang scope. Gayunpaman, ang malaking bilang ng coroutine ay maaaring magpahiwatig ng mga problema sa arkitektura.

Paano subukan ang code na may CoroutineScope?

Ang tamang paraan ay ipasa ang scope sa klase sa pamamagitan ng constructor o gamitin ang runBlockingTest / runTest mula sa kotlinx-coroutines-test. Sa mga pagsubok, maaari mong palitan ang scope ng TestCoroutineDispatcher at manu-manong kontrolin ang pagpapatupad ng coroutine.

Maaari bang magkaroon ng sariling scope ang isang coroutine?

Hindi, ang scope ay isang panlabas na lalagyan para sa coroutine. Ang coroutine mismo ay hindi isang scope. Gayunpaman, sa loob ng coroutine, maaaring lumikha ng bagong scope sa pamamagitan ng coroutineScope o supervisorScope para sa parallel na paglulunsad ng mga coroutine na anak.

Buod

  • CoroutineScope — interface na may field na coroutineContext, na tumutukoy sa siklo ng buhay ng mga coroutine na inilunsad dito
  • Konkurensiyang struktural — pagkansela ng scope ay awtomatikong kinakansela ang lahat ng coroutine na anak, pumipigil sa pagtagas ng memorya
  • Job at SupervisorJob — dalawang mode ng pangangasiwa ng error: cascading cancellation (Job) at isolated errors (SupervisorJob)
  • GlobalScope — hindi inirerekomenda para sa production dahil sa kakulangan ng pagtatali sa siklo ng buhay
  • coroutineScope vs supervisorScope — atomikong parallel na operasyon laban sa independiyenteng parallel na gawain
  • viewModelScope at lifecycleScope — mga handa nang scope para sa Android, awtomatikong kinakansela kapag natapos ang bahagi
  • Factory function — mas ginustong paraan ng paglikha ng scope sa pamamagitan ng CoroutineContext + tahasang tawag ng cancel

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din