withContext — एक कोरूटीन के अंदर कॉन्टेक्स्ट स्विच करने वाला फ़ंक्शन है जो कोड के दिए गए ब्लॉक के लिए अस्थायी रूप से थ्रेड या डिस्पैचर बदलता है और परिणाम मूल कॉन्टेक्स्ट में वापस लौटाता है। JetBrains, 2025 के अनुसार, withContext नेटवर्क अनुरोधों और डिस्क ऑपरेशनों के लिए सबसे अधिक उपयोग किए जाने वाले कोरूटीन टूल में से एक है। फ़ंक्शन गारंटी देता है कि ब्लॉक पूरा होने के बाद कोरूटीन मूल डिस्पैचर पर निष्पादन जारी रखता है, जो आकस्मिक थ्रेड-सुरक्षा त्रुटियों को रोकता है।
मुख्य बातें
withContext kotlinx.coroutines पैकेज से एक सस्पेंडिंग फ़ंक्शन है जो कोड के दिए गए ब्लॉक को एक निर्दिष्ट CoroutineContext में निष्पादित करता है और परिणाम मूल कॉन्टेक्स्ट में लौटाता है। फ़ंक्शन का सिग्नेचर इस प्रकार है:
suspend fun withContext (
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T
context पैरामीटर किसी भी CoroutineContext को स्वीकार करता है — आमतौर पर मानक Dispatchers.IO, Dispatchers.Default या Dispatchers.Main में से एक। ब्लॉक उस कॉन्टेक्स्ट में निष्पादित होता है, और परिणाम वहाँ लौटाया जाता है जहाँ से withContext कॉल किया गया था।
लैम्ब्डा पूरा होने के बाद, withContext गारंटीपूर्वक निष्पादन को मूल डिस्पैचर पर वापस स्विच करता है। इसका मतलब है कि डेवलपर को बैकग्राउंड ऑपरेशन के बाद मैन्युअल रूप से withContext(Dispatchers.Main) कॉल करने की आवश्यकता नहीं है — वापसी स्वचालित रूप से होती है। यह व्यवहार Kotlin Coroutines विनिर्देश में संस्करण 1.3 से दस्तावेज़ित है।
Android डेवलपमेंट withContext के उपयोग का मुख्य क्षेत्र है। एक विशिष्ट परिदृश्य: ViewModel मुख्य थ्रेड पर एक कोरूटीन शुरू करता है, उसके अंदर नेटवर्क अनुरोध के लिए withContext(Dispatchers.IO) कॉल करता है, और Main पर स्वचालित वापसी के बाद परिणाम UI को अपडेट करने के लिए उपयोग किया जाता है। यह दृष्टिकोण MVVM आर्किटेक्चर की नींव है और Google द्वारा आधिकारिक कोरूटीन गाइड में अनुशंसित है।
withContext को समझने के लिए, आपको CoroutineContext और इसके प्रमुख घटक — डिस्पैचर को समझना होगा। प्रत्येक कोरूटीन में कॉन्टेक्स्ट तत्वों का एक सेट होता है, जिसमें से डिस्पैचर यह निर्धारित करता है कि कोड किस थ्रेड या थ्रेड पूल पर चलेगा।
| डिस्पैचर | उद्देश्य | पूल आकार |
|---|---|---|
| Dispatchers.Main | मुख्य UI थ्रेड (Android, JavaFX, Swing) | 1 (मुख्य थ्रेड) |
| Dispatchers.IO | डिस्क और नेटवर्क ऑपरेशन | 64 थ्रेड (सीमा बढ़ती है) |
| Dispatchers.Default | CPU-गहन गणनाएँ | max(2, कोर की संख्या) |
| Dispatchers.Unconfined | कोई निश्चित थ्रेड नहीं | असीमित |
यह समझना महत्वपूर्ण है कि withContext एक नया कोरूटीन नहीं बनाता — यह केवल मौजूदा कोरूटीन का कॉन्टेक्स्ट बदलता है। यह launch और async से मुख्य अंतर है, जो नए कोरूटीन उत्पन्न करते हैं। withContext का आंतरिक कार्यान्वयन अनुकूलित है: यदि अनुरोधित कॉन्टेक्स्ट वर्तमान से मेल खाता है, तो कोई स्विचिंग नहीं होती — फ़ंक्शन उसी डिस्पैचर पर निष्पादित होता है।
Dispatchers.Main withContext(Dispatchers.Main) के अंदर स्विच नहीं करता — Kotlin Coroutines कॉन्टेक्स्ट की समानता को पहचानता है और अनावश्यक संचालन को छोड़ देता है। इसी तरह, withContext(Dispatchers.Default) पहले से Default पर चल रहे कोरूटीन के अंदर कोई ओवरहेड नहीं बनाता। यह अनुकूलन ContinuationInterceptor में कार्यान्वित है।
शुरुआती अक्सर withContext को launch और async के साथ भ्रमित करते हैं, क्योंकि तीनों फ़ंक्शन कोरूटीन और कॉन्टेक्स्ट के साथ काम करते हैं। हालाँकि, उनका उद्देश्य मौलिक रूप से भिन्न है।
| विशेषता | withContext | launch | async |
|---|---|---|---|
| नया कोरूटीन बनाता है | नहीं | हाँ | हाँ |
| परिणाम लौटाता है | हाँ (T सीधे) | नहीं (Job) | हाँ (Deferred<T>) |
| निष्पादन | अनुक्रमिक | समानांतर | समानांतर |
| परिणाम की प्रतीक्षा | स्वचालित | join() | await() |
| विशिष्ट उपयोग-मामला | डिस्पैचर बदलना | फायर-एंड-फ़ॉरगेट | समानांतर गणनाएँ |
यदि आपको बैकग्राउंड थ्रेड पर एक ऑपरेशन निष्पादित करना है और परिणाम प्राप्त करना है — withContext का उपयोग करें। यदि आपको कई स्वतंत्र ऑपरेशन समानांतर में चलाने हैं — await के साथ async का उपयोग करें। यदि परिणाम की आवश्यकता नहीं है (लॉगिंग, कैश लिखना) — launch का उपयोग करें। Google Android आर्किटेक्चर में Repository परत के लिए withContext को पसंदीदा टूल के रूप में अनुशंसित करता है।
आइए Kotlin Android एप्लिकेशन में withContext के उपयोग के तीन व्यावहारिक परिदृश्य देखें। प्रत्येक उदाहरण एक विशिष्ट कार्य और सही पैटर्न प्रदर्शित करता है।
ViewModel Main पर कोरूटीन से रिपॉजिटरी मेथड कॉल करता है। अंदर, withContext(Dispatchers.IO) HTTP अनुरोध करता है, और परिणाम स्वचालित रूप से लौटाया जाता है:
class UserRepository(
private val api: UserApi
) {
suspend fun getUser(id: String): User {
return withContext(Dispatchers.IO) {
api.fetchUser(id)
}
}
}
ViewModel में कोरूटीन getUser को किसी भी सामान्य सस्पेंडिंग फ़ंक्शन की तरह कॉल करता है — बिना डिस्पैचर स्पष्ट रूप से निर्दिष्ट किए। withContext थ्रेड स्विचिंग के विवरण छिपाता है।
जब आपको एक के बाद एक कई IO ऑपरेशन करने की आवश्यकता होती है, withContext उन्हें एक ही ब्लॉक में जोड़ता है। यह प्रत्येक ऑपरेशन को अलग withContext में लपेटने से अधिक कुशल है:
suspend fun loadUserProfile(id: String): Profile {
return withContext(Dispatchers.IO) {
val user = api.fetchUser(id)
val posts = api.fetchPosts(id)
Profile(user, posts)
}
}
दोनों ऑपरेशन Dispatchers.IO पर चलते हैं, और Profile परिणाम बिना अनावश्यक कॉन्टेक्स्ट स्विच के बनाया और लौटाया जाता है। यदि ऑपरेशन स्वतंत्र हैं, तो समानांतर निष्पादन के लिए async का उपयोग करना बेहतर है।
कुछ परिदृश्यों में, आपको ऐसा कोड निष्पादित करने की आवश्यकता होती है जिसे रद्द नहीं किया जा सकता — उदाहरण के लिए, स्क्रीन बंद करते समय स्थिति सहेजना। withContext + NonCancellable का संयोजन इस कार्य को हल करता है:
withContext(Dispatchers.IO + NonCancellable) {
cache.saveState(state)
analytics.logEvent("state_saved")
}
ऑपरेटर + दो कॉन्टेक्स्ट तत्वों को जोड़ता है: IO डिस्पैचर और NonCancellable फ़्लैग। ब्लॉक तब भी निष्पादित होता है भले ही पैरेंट कोरूटीन रद्द कर दिया गया हो — फ़ाइनलाइज़िंग ऑपरेशन के लिए उपयोगी।
withContext का आंतरिक कार्यान्वयन Continuation तंत्र पर आधारित है — Kotlin कोरूटीन का केंद्रीय एब्स्ट्रैक्शन। प्रत्येक सस्पेंड पॉइंट निष्पादन स्थिति को Continuation ऑब्जेक्ट में सहेजता है, और withContext कोई अपवाद नहीं है।
Kotlin कंपाइलर withContext को kotlinx.coroutines से withContext मेथड कॉल में अनुवादित करता है, जो आंतरिक रूप से DispatchedContinuation का एक नया इंस्टेंस बनाता है। यह ऑब्जेक्ट मूल Continuation को लपेटता है और उसके डिस्पैचर को बदलता है। यदि नया डिस्पैचर वर्तमान से भिन्न है, तो निष्पादन निलंबित हो जाता है, ब्लॉक संबंधित थ्रेड पूल को भेजा जाता है, और पूरा होने के बाद — मूल कॉन्टेक्स्ट के साथ फिर से शुरू होता है।
जब withContext उसी डिस्पैचर के साथ कॉल किया जाता है जिस पर कोरूटीन पहले से चल रहा है, Kotlin फ़ास्ट-पाथ (fast-path) सक्रिय करता है: ब्लॉक सिंक्रोनस रूप से निष्पादित होता है, बिना DispatchedContinuation बनाए और बिना थ्रेड पूल को भेजे। यह withContext को समान कॉन्टेक्स्ट के साथ बार-बार कॉल के लिए व्यावहारिक रूप से मुफ़्त बनाता है। JetBrains बेंचमार्क (kotlinx.coroutines 1.8) के अनुसार, फ़ास्ट-पाथ 0.1 µs से कम में पूरा होता है।
withContext का प्रत्येक कॉल भिन्न डिस्पैचर के साथ एक नया DispatchedContinuation बनाता है और थ्रेड स्विचिंग की आवश्यकता होती है — इसमें लोड के आधार पर 1 से 5 µs लगते हैं। अधिकांश एप्लिकेशन के लिए यह देरी अदृश्य है, लेकिन हजारों पुनरावृत्तियों वाले लूप के अंदर, संचालन को एक withContext ब्लॉक में एकत्रित करना उचित है।
अनुभवी डेवलपर भी withContext के साथ काम करते समय गलतियाँ करते हैं। आइए चार सबसे सामान्य समस्याएँ और उन्हें रोकने के तरीके देखें।
डेवलपर अक्सर प्रत्येक पंक्ति को अलग withContext में लपेटते हैं, बजाय इसके कि संचालन को एक ब्लॉक में संयोजित करें। भिन्न डिस्पैचर के साथ प्रत्येक अतिरिक्त कॉल ओवरहेड बनाता है।
सही: अनुक्रमिक IO संचालन को एक withContext(Dispatchers.IO) { ... } में संयोजित करें। यदि कुछ संचालन CPU-गहन हैं — उसी ब्लॉक के अंदर withContext(Dispatchers.Default) का उपयोग करें।
withContext कोड को अनुक्रमिक रूप से निष्पादित करता है। यदि दो स्वतंत्र नेटवर्क अनुरोध एक withContext में लपेटे गए हैं, तो वे एक के बाद एक चलेंगे। समानांतरता के लिए, async + await का उपयोग करें।
// अनुक्रमिक — धीमा
withContext(Dispatchers.IO) {
val a = api.fetchA()
val b = api.fetchB()
}
// समानांतर — तेज़
coroutineScope {
val a = async { api.fetchA() }
val b = async { api.fetchB() }
println("${a.await()} ${b.await()}")
}
यदि कोरूटीन withContext के दौरान रद्द कर दिया जाता है, तो Dispatchers.IO पर ब्लॉक भी बाधित होता है। उन संचालनों के लिए जो किसी भी कीमत पर पूरे होने चाहिए (डेटाबेस लेखन, एनालिटिक्स सबमिशन), withContext को NonCancellable के साथ संयोजित करें।
कभी भी withContext(Dispatchers.IO) के अंदर View घटकों को अपडेट न करें। withContext पूरे ब्लॉक के पूरा होने तक Main पर वापस नहीं आता। UI अपडेट को withContext के बंद होने वाले ब्रेस के बाद रखें — तब कोरूटीन पहले से मुख्य थ्रेड पर होगा।
अक्सर पूछे जाने वाले प्रश्न
withContext एक सस्पेंडिंग फ़ंक्शन है जो थ्रेड को ब्लॉक नहीं करता, बल्कि मौजूदा कोरूटीन के अंदर कॉन्टेक्स्ट बदलता है। runBlocking कोरूटीन और सामान्य कोड के बीच एक पुल है जो पूरा होने तक वर्तमान थ्रेड को ब्लॉक करता है। withContext UI थ्रेड के लिए सुरक्षित है, runBlocking नहीं।
नहीं, withContext एक suspend फ़ंक्शन है, इसलिए इसे केवल दूसरे suspend फ़ंक्शन या कोरूटीन (launch/async) से ही कॉल किया जा सकता है। सामान्य फ़ंक्शन से withContext कॉल नहीं किया जा सकता — इसके लिए runBlocking या CoroutineScope की आवश्यकता है।
Kotlin फ़ास्ट-पाथ (fast-path) सक्रिय करता है — ब्लॉक उसी थ्रेड पर सिंक्रोनस रूप से बिना स्विचिंग के निष्पादित होता है। ओवरहेड 0.1 µs से कम है। यह कोई त्रुटि नहीं है, लेकिन ऐसा कॉल अनावश्यक है — बिना withContext के कोड निष्पादित करना बेहतर है।
withContext के अंदर अपवाद सामान्य कोड की तरह ही प्रसारित होते हैं — try-catch के माध्यम से। यदि ब्लॉक एक अपवाद फेंकता है, तो यह पैरेंट कोरूटीन में प्रसारित होता है और यदि संभाला नहीं गया तो इसे रद्द कर देता है। withContext के अंदर या उसके आसपास try-catch का उपयोग करें।
नहीं, withContext एक नया कोरूटीन नहीं बनाता। यह मौजूदा कोरूटीन का उपयोग करता है लेकिन अस्थायी रूप से उसका कॉन्टेक्स्ट बदलता है। यह इसे launch और async से अलग करता है, जो चाइल्ड कोरूटीन उत्पन्न करते हैं। यह व्यवहार kotlinx.coroutines सोर्स कोड द्वारा पुष्टि किया गया है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें