withContext — korutina ichida bajarilish kontekstini almashtiruvchi funksiya bo'lib, ko'rsatilgan kod bloki uchun vaqtinchalik oqim yoki dispetcherni o'zgartiradi va natijani asl kontekstga qaytaradi. JetBrains, 2025 ma'lumotlariga ko'ra, withContext tarmoq so'rovlari va disk operatsiyalari uchun korutinalarning eng ko'p ishlatiladigan vositalaridan biridir. Funksiya blok tugagandan so'ng korutinaning asl dispetcherda bajarilishni davom ettirishini kafolatlaydi, bu esa tasodifiy oqim xavfsizligi xatolarining oldini oladi.
Asosiy fikrlar
withContext — kotlinx.coroutines paketidan to'xtatuvchi funksiya bo'lib, berilgan kod blokini belgilangan CoroutineContext-da bajaradi va natijani asl kontekstga qaytaradi. Funksiya imzosi quyidagicha:
suspend fun withContext (
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T
context parametri istalgan CoroutineContext-ni qabul qiladi — ko'pincha standart Dispatchers.IO, Dispatchers.Default yoki Dispatchers.Main dan biri. Blok aynan shu kontekstda bajariladi va natija withContext chaqirilgan joyga qaytariladi.
Lambda tugagandan so'ng, withContext kafolatlangan holda bajarilishni asl dispetcherga qaytaradi. Bu shuni anglatadiki, dasturchi fon operatsiyasidan so'ng qo'lda withContext(Dispatchers.Main) chaqirishi shart emas — qaytish avtomatik sodir bo'ladi. Ushbu xatti-harakat Kotlin Coroutines spetsifikatsiyasida 1.3 versiyasidan boshlab belgilangan.
Android rivojlanishi — withContext ning asosiy qo'llanish sohasi. Odatiy stsenariy: ViewModel asosiy oqimda korutina ishga tushiradi, ichida tarmoq so'rovi uchun withContext(Dispatchers.IO) chaqiriladi va natija Main-ga avtomatik qaytgandan so'ng UI ni yangilash uchun ishlatiladi. Ushbu yondashuv MVVM arxitekturasining asosini tashkil etadi va Google tomonidan korutinalar bo'yicha rasmiy qo'llanmada tavsiya etiladi.
withContext ni tushunish uchun CoroutineContext va uning asosiy komponenti — dispetcher (Dispatcher) bilan tanishish kerak. Har bir korutina kontekst elementlari to'plamiga ega bo'lib, ular orasida dispetcher kod qaysi oqim yoki oqimlar havzasida bajarilishini aniqlaydi.
| Dispetcher | Maqsad | Havza hajmi |
|---|---|---|
| Dispatchers.Main | Asosiy UI oqimi (Android, JavaFX, Swing) | 1 (asosiy oqim) |
| Dispatchers.IO | Disk va tarmoq operatsiyalari | 64 oqim (chegara o'sadi) |
| Dispatchers.Default | CPU intensiv hisoblashlar | max(2, yadrolar soni) |
| Dispatchers.Unconfined | Ruxsat etilgan oqimsiz | cheklanmagan |
withContext yangi korutina yaratmasligini tushunish muhim — u faqat mavjud korutina uchun kontekstni o'zgartiradi. Bu uni launch va async-dan farqlaydigan asosiy xususiyatdir, chunki ular yangi korutinalar yaratadi. Ichki amalga oshirish optimallashtirilgan: so'ralgan kontekst joriy bilan mos kelsa, almashtirish sodir bo'lmaydi — funksiya bir xil dispetcherda bajariladi.
Dispatchers.Main withContext(Dispatchers.Main) ichida almashtirishga sabab bo'lmaydi — Kotlin Coroutines kontekstlarning bir xilligini taniydi va keraksiz operatsiyani o'tkazib yuboradi. Xuddi shunday, allaqachon Default-da ishlayotgan korutina ichida withContext(Dispatchers.Default) hech qanday qo'shimcha yuk yaratmaydi. Ushbu optimallashtirish ContinuationInterceptor da amalga oshirilgan.
Yangi boshlanuvchilar tez-tez withContext ni launch va async bilan aralashtiradilar, chunki uchala funksiya ham korutinalar va kontekst bilan ishlaydi. Biroq, ularning maqsadi tubdan farq qiladi.
| Xususiyat | withContext | launch | async |
|---|---|---|---|
| Yangi korutina yaratadi | Yo'q | Ha | Ha |
| Natija qaytaradi | Ha (T to'g'ridan-to'g'ri) | Yo'q (Job) | Ha (Deferred<T>) |
| Bajarilishi | Ketma-ket | Parallel | Parallel |
| Natijani kutish | Avtomatik | join() | await() |
| Odatiy foydalanish | Dispetcher almashtirish | Fire-and-forget | Parallel hisoblashlar |
Agar fon oqimida bitta operatsiya bajarib natija olish kerak bo'lsa — withContext dan foydalaning. Agar bir nechta mustaqil operatsiyalarni parallel ishga tushirish kerak bo'lsa — async bilan await dan foydalaning. Agar natija kerak bo'lmasa (loglash, kesh yozish) — launch. Google Android arxitekturasida Repository qatlami uchun withContext ni afzal ko'rilgan vosita sifatida tavsiya qiladi.
Kotlin tilida Android ilovalarida withContext dan foydalanishning uchta amaliy stsenariysini ko'rib chiqamiz. Har bir misol aniq vazifa va to'g'ri shablonni ko'rsatadi.
ViewModel repository usulini Main-dagi korutinadan chaqiradi. Ichida withContext(Dispatchers.IO) HTTP so'rovini bajaradi va natija avtomatik qaytariladi:
class UserRepository(
private val api: UserApi
) {
suspend fun getUser(id: String): User {
return withContext(Dispatchers.IO) {
api.fetchUser(id)
}
}
}
ViewModel-dagi korutina getUser ni oddiy to'xtatuvchi funksiya kabi chaqiradi — dispetcherni aniq ko'rsatmasdan. withContext oqimni almashtirish tafsilotlarini yashiradi.
Bir nechta IO operatsiyalarini ketma-ket bajarish kerak bo'lganda, withContext ularni yagona blokda birlashtiradi. Bu har bir operatsiyani alohida withContext ga o'rashdan ko'ra samaraliroq:
suspend fun loadUserProfile(id: String): Profile {
return withContext(Dispatchers.IO) {
val user = api.fetchUser(id)
val posts = api.fetchPosts(id)
Profile(user, posts)
}
}
Ikkala operatsiya Dispatchers.IO da bajariladi va Profile natijasi keraksiz kontekst almashtirishlarsiz yaratilib qaytariladi. Agar operatsiyalar mustaqil bo'lsa, parallel bajarish uchun async dan foydalanish yaxshiroq.
Ba'zi stsenariylarda bekor qilib bo'lmaydigan kodni bajarish kerak — masalan, ekran yopilganda holatni saqlash. withContext + NonCancellable kombinatsiyasi bu vazifani hal qiladi:
withContext(Dispatchers.IO + NonCancellable) {
cache.saveState(state)
analytics.logEvent("state_saved")
}
+ operatori ikkita kontekst elementini birlashtiradi: IO dispetcheri va NonCancellable bayrog'i. Blok ota korutina bekor qilingan taqdirda ham bajariladi — bu yakuniy operatsiyalar uchun foydali.
withContext ning ichki amalga oshirilishi Continuation mexanizmiga — Kotlin korutinalarining markaziy abstraksiyasiga tayanadi. Har bir to'xtash nuqtasi (suspend point) bajarilish holatini Continuation ob'ektida saqlaydi va withContext bundan mustasno emas.
Kotlin kompilyatori withContext ni kotlinx.coroutines dan withContext metodiga chaqiruv sifatida tarjima qiladi, u ichki qismida yangi DispatchedContinuation namunasini yaratadi. Ushbu ob'ekt asl Continuation ni o'rab oladi va undagi dispetcherni almashtiradi. Agar yangi dispetcher joriydan farq qilsa, bajarilish to'xtatiladi, blok tegishli oqimlar havzasiga yuboriladi va tugagandan so'ng asl kontekst bilan qayta boshlanadi.
withContext korutina allaqachon ishlayotgan bir xil dispetcher bilan chaqirilganda, Kotlin fast-path ni ishga soladi: blok sinxron tarzda, DispatchedContinuation yaratmasdan va oqimlar havzasiga jo'natmasdan bajariladi. Bu withContext ni bir xil kontekst bilan takroriy chaqiruvlarda amalda tekin qiladi. JetBrains benchmarklariga ko'ra (kotlinx.coroutines 1.8), fast-path 0,1 mks dan kam vaqtda bajariladi.
Farqli dispetcher bilan har bir withContext chaqiruvi yangi DispatchedContinuation yaratadi va oqimni almashtirishni talab qiladi — bu yukga qarab 1 dan 5 mks gacha vaqt oladi. Ko'pgina ilovalar uchun bu kechikish sezilmaydi, ammo minglab iteratsiyali sikllarda operatsiyalarni bitta withContext blokida to'plash yaxshiroqdir.
Hatto tajribali dasturchilar ham withContext bilan ishlashda xato qiladilar. Eng keng tarqalgan to'rtta muammo va ularning oldini olish usullarini ko'rib chiqamiz.
Dasturchilar ko'pincha har bir qatorni alohida withContext ga o'raydilar, operatsiyalarni bir blokda birlashtirish o'rniga. Farqli dispetcher bilan har bir qo'shimcha chaqiruv qo'shimcha yuk yaratadi.
To'g'ri: ketma-ket IO operatsiyalarini bitta withContext(Dispatchers.IO) { ... } blokida birlashtiring. Agar operatsiyalarning bir qismi CPU intensiv bo'lsa — xuddi shu blok ichida withContext(Dispatchers.Default) dan foydalaning.
withContext kodni ketma-ket bajaradi. Agar ikkita mustaqil tarmoq so'rovi bitta withContext ga o'ralgan bo'lsa, ular birin-ketin bajariladi. Parallel uchun async + await dan foydalaning.
// Ketma-ket — sekin
withContext(Dispatchers.IO) {
val a = api.fetchA()
val b = api.fetchB()
}
// Parallel — tez
coroutineScope {
val a = async { api.fetchA() }
val b = async { api.fetchB() }
println("${a.await()} ${b.await()}")
}
withContext vaqtida korutina bekor qilinsa, Dispatchers.IO dagi blok ham to'xtatiladi. Har qanday holatda ham tugatilishi kerak bo'lgan operatsiyalar uchun (ma'lumotlar bazasiga yozish, analitika jo'natish) withContext ni NonCancellable bilan birlashtiring.
Hech qachon View komponentlarini withContext(Dispatchers.IO) ichida yangilamang. withContext butun blok tugaguncha Main ga qaytmaydi. UI yangilashni withContext ning yopuvchi qavsidan keyin bajaring — u holda korutina allaqachon asosiy oqimda bo'ladi.
Ko'p beriladigan savollar
withContext — oqimni bloklamaydigan, balki mavjud korutina ichida kontekstni almashtiradigan to'xtatuvchi funksiya. runBlocking — korutinalar va oddiy kod o'rtasidagi ko'prik bo'lib, joriy oqimni tugaguncha bloklaydi. withContext UI oqimi uchun xavfsiz, runBlocking esa yo'q.
Yo'q, withContext to'xtatuvchi funksiyadir, shuning uchun uni faqat boshqa to'xtatuvchi funksiyadan yoki korutinadan (launch/async) chaqirish mumkin. Oddiy funksiyadan withContext chaqirilmaydi — buning uchun runBlocking yoki CoroutineScope kerak.
Kotlin fast-path ni faollashtiradi — blok bir xil oqimda sinxron tarzda almashtirilmasdan bajariladi. Qo'shimcha yuk 0,1 mks dan kam. Bu xato emas, ammo bunday chaqiruv ortiqcha — kodni withContext siz bajarish yaxshiroq.
withContext ichidagi istisnolar oddiy koddagidek — try-catch orqali tarqaladi. Agar blok istisno tashlasa, u ota korutinaga tarqaladi va ishlov berilmasa uni bekor qiladi. withContext ichida yoki uning atrofida try-catch dan foydalaning.
Yo'q, withContext yangi korutina yaratmaydi. U mavjud korutinadan foydalanadi, lekin vaqtincha uning kontekstini o'zgartiradi. Bu uni launch va async dan farqlaydi, chunki ular bola korutinalar yaratadi. Xatti-harakat kotlinx.coroutines manba kodi bilan tasdiqlangan.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.