CoroutineScope — adalah antarmuka Kotlin yang menentukan cakupan hidup coroutine dan menyediakan konteks untuk meluncurkan coroutine baru. Menurut dokumentasi Kotlin, 2025, setiap instance CoroutineScope berisi CoroutineContext dan mengelola semua coroutine yang diluncurkan di dalamnya. Ketika scope berakhir (cancel), semua coroutine anak secara otomatis dibatalkan, mencegah kebocoran memori.
Poin Penting
CoroutineScope — adalah antarmuka fundamental dari pustaka kotlinx.coroutines yang berfungsi sebagai wadah untuk coroutine. Ini menentukan batas hidup coroutine: ketika scope berakhir, semua coroutine di dalamnya secara otomatis dibatalkan.
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
Antarmuka hanya berisi satu bidang — coroutineContext. Melaluinya, scope menyediakan dispatcher (Dispatcher), tugas (Job), penanganan pengecualian, dan elemen konteks lainnya untuk semua coroutine yang diluncurkan di dalamnya.
Semua fungsi peluncuran coroutine — launch, async, runBlocking — adalah fungsi ekstensi pada CoroutineScope. Ini berarti mereka hanya dapat dipanggil jika ada objek scope. Desain semacam itu menjamin bahwa setiap coroutine memiliki induk dan siklus hidup yang ditentukan dengan jelas.
Di Android, setiap komponen arsitektur memiliki scope sendiri: viewModelScope untuk ViewModel, lifecycleScope untuk Activity/Fragment. Di aplikasi server, scope dapat dikaitkan dengan permintaan HTTP atau dengan kumpulan koneksi basis data.
Memahami struktur internal CoroutineScope memerlukan keakraban dengan konsep Job dan prinsip konkurensi struktural.
Setiap coroutine saat diluncurkan mengembalikan objek Job (atau Deferred untuk async). Job mewakili tugas dengan siklus hidup yang ditentukan: New, Active, Completing, Completed, Cancelling, Cancelled. Objek Job membentuk struktur pohon:
Konkurensi struktural — prinsip arsitektur utama Kotlin Coroutines, di mana masa hidup coroutine terikat pada masa hidup scope-nya. Ini kontras dengan model “fire-and-forget”, di mana coroutine terus hidup setelah scope berakhir. Keuntungan konkurensi struktural:
Ketika scope.cancel() dipanggil, Job scope masuk ke status Cancelled, yang secara rekursif membatalkan semua Job anak. Setelah pembatalan, scope hanya dapat digunakan kembali dengan membuat instance CoroutineScope baru.
CoroutineScope dapat dibuat melalui fungsi pabrik atau melalui implementasi antarmuka di kelas Anda. Mari kita bahas kedua pendekatan.
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
scope.launch {
println("Berjalan di ${Thread.currentThread().name}")
}
Fungsi pabrik menerima CoroutineContext dan membuat scope dengan konteks yang ditentukan. Dalam contoh, digunakan Dispatchers.Default untuk tugas intensif CPU dan SupervisorJob yang mengisolasi pengecualian antara coroutine anak.
class MyRepository {
private val scope = CoroutineScope(Dispatchers.IO + Job())
suspend fun fetchData(): Data = scope.async {
api.getData()
}.await()
fun cleanup() {
scope.cancel()
}
}
Kami menyimpan scope sebagai bidang kelas dan secara manual memanggil cleanup untuk membatalkannya. Ini cocok untuk komponen dengan siklus hidup terkelola — misalnya, untuk repositori atau manajer.
Kotlin memungkinkan delegasi implementasi CoroutineScope melalui kata kunci by:
class DataLoader : CoroutineScope by CoroutineScope(Dispatchers.IO) {
fun load() {
launch {
// coroutine berjalan di scope DataLoader
}
}
}
Pendekatan ini nyaman ketika kelas itu sendiri adalah scope dan ingin menyediakan metode peluncuran coroutine. Namun berhati-hatilah: kelas mewarisi semua metode CoroutineScope, termasuk cancel, yang dapat melanggar enkapsulasi.
GlobalScope — adalah singleton CoroutineScope untuk seluruh aplikasi. Penggunaannya dalam kode produksi secara resmi tidak direkomendasikan.
JetBrains mengizinkan GlobalScope hanya dalam skenario langka: proses latar belakang tingkat aplikasi yang harus tetap hidup bahkan setelah semua Activity ditutup (misalnya, sinkronisasi data, analitik). Tetapi bahkan dalam kasus ini, lebih baik membuat scope sendiri dengan CoroutineScope(SupervisorJob()).
Selalu gunakan CoroutineScope kustom dengan manajemen siklus hidup yang eksplisit. Di Android, ini adalah viewModelScope dan lifecycleScope. Di aplikasi server, buat scope untuk setiap permintaan atau kumpulan koneksi.
Kedua fungsi adalah fungsi suspend yang membuat scope sementara untuk tugas paralel, tetapi perilaku mereka saat pengecualian pada dasarnya berbeda.
| Karakteristik | coroutineScope | supervisorScope |
|---|---|---|
| Perilaku saat kesalahan | Pengecualian di coroutine anak membatalkan semua yang lain | Pengecualian di coroutine anak TIDAK membatalkan yang lain |
| Penyebaran kesalahan | Ya, pengecualian pertama disebarkan ke luar | Ya, pengecualian pertama disebarkan ke luar |
| Job default | Job() — anak terikat pada induk | SupervisorJob() — anak tidak bergantung satu sama lain |
| Use-case tipikal | Operasi atom dari beberapa langkah | Tugas paralel independen (muatan UI) |
Gunakan coroutineScope ketika beberapa operasi paralel membentuk satu operasi atom. Misalnya, memuat data dari tiga server: jika satu permintaan gagal, yang lain tidak berarti.
suspend fun loadProductPage(): ProductPage = coroutineScope {
val product = async { api.getProduct() }
val reviews = async { api.getReviews() }
ProductPage(product.await(), reviews.await())
}
Jika getProduct atau getReviews melempar pengecualian — kedua coroutine dibatalkan, dan pengecualian disebarkan ke kode pemanggil.
Gunakan supervisorScope ketika operasi paralel tidak bergantung satu sama lain. Misalnya, memuat data profil di beberapa bagian independen: jika bagian rekomendasi gagal, tajuk profil dan daftar teman harus ditampilkan.
Mari kita bahas kesalahan paling umum pengembang saat menggunakan CoroutineScope di Kotlin.
Skenario kebocoran coroutine yang paling umum — membuat scope tanpa memanggil cancel saat komponen berakhir. Jika scope tidak dibatalkan, coroutine terus berjalan, menyimpan referensi ke objek. Di Android, gunakan viewModelScope atau lifecycleScope, yang dibatalkan secara otomatis.
GlobalScope mengabaikan siklus hidup komponen Android. Coroutine yang diluncurkan di GlobalScope setelah Activity ditutup akan terus berjalan dan mencoba memperbarui UI — yang menyebabkan crash. Selalu gunakan lifecycleScope untuk komponen UI.
Setelah memanggil cancel(), scope tidak dapat digunakan kembali — semua coroutine di dalamnya sudah selesai. Buat instance CoroutineScope baru melalui fungsi pabrik. Job() tidak mendukung aktivasi ulang.
Saat delegasi melalui by, kelas mendapatkan metode publik cancel() yang dapat dipanggil dari mana saja, melanggar enkapsulasi. Simpan scope sebagai bidang privat, jangan delegasikan antarmuka.
Pertanyaan yang Sering Diajukan
CoroutineScope — adalah antarmuka yang memiliki CoroutineContext dan bertanggung jawab atas siklus hidup coroutine. CoroutineContext — adalah kumpulan elemen (dispatcher, job, penanganan kesalahan) yang menentukan “bagaimana” coroutine dijalankan. Salah satu perbedaannya: scope membuat coroutine, context mengelola perilaku mereka.
Ya, ini adalah pola standar: CoroutineScope(Dispatchers.IO + SupervisorJob()). SupervisorJob mencegah pembatalan berantai coroutine anak saat pengecualian di salah satunya. Ini berguna untuk tugas paralel independen di mana kesalahan pada satu tidak boleh menghentikan yang lain.
Tidak ada batasan jumlah coroutine dalam scope — mereka hanya dibatasi oleh memori yang tersedia dan pengaturan dispatcher. Batas praktis biasanya ribuan coroutine aktif dalam satu scope. Namun, jumlah coroutine yang besar dapat menunjukkan masalah arsitektur.
Cara yang benar adalah meneruskan scope ke kelas melalui konstruktor atau menggunakan runBlockingTest / runTest dari kotlinx-coroutines-test. Dalam pengujian, Anda dapat mengganti scope dengan TestCoroutineDispatcher dan mengontrol eksekusi coroutine secara manual.
Tidak, scope adalah wadah eksternal untuk coroutine. Coroutine itu sendiri bukan scope. Namun, di dalam coroutine, scope baru dapat dibuat melalui coroutineScope atau supervisorScope untuk meluncurkan coroutine anak secara paralel.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga