Kotlin कोरूटीन आपको साफ़ और आसान एसिंक्रोनस कोड लिखने में मदद करता है, जो लंबे समय तक चलने वाले टास्क मैनेज करते समय, जैसे कि नेटवर्क कॉल की प्रक्रिया भी हो सकती है.
यह विषय, Android पर कोरूटीन के बारे में ज़्यादा जानकारी देता है. अगर आप: कोरूटीन के बारे में कोई जानकारी नहीं है, तो इस विषय को पढ़ने से पहले, Android पर Kotlin कोरूटीन.
लंबे समय तक चलने वाले टास्क मैनेज करें
दो ऑपरेशन जोड़ने से, नियमित फ़ंक्शन को हैंडल करने के लिए कोरूटीन तैयार होते हैं
लंबे समय तक चलने वाले टास्क. invoke
(या call
) और return
के अलावा,
कोरूटीन, suspend
और resume
को जोड़ते हैं:
suspend
, मौजूदा कोरूटीन के एक्ज़ीक्यूशन को रोक देता है. साथ ही, सभी लोकल कैश मेमोरी में सेव किया जाता है वैरिएबल.resume
, यहां से निलंबित कोरूटीन को चलाना जारी रखता है जहां इसे निलंबित कर दिया गया था.
आपके पास सिर्फ़ अन्य suspend
फ़ंक्शन से या suspend
फ़ंक्शन को कॉल करने का विकल्प है
नया कोरूटीन शुरू करने के लिए, launch
जैसे कोरूटीन बिल्डर का इस्तेमाल किया जा सकता है.
नीचे दिए गए उदाहरण में, एक सामान्य कोरूटीन को लागू करने के बारे में बताया गया है. लंबे समय तक चलने वाला काल्पनिक टास्क:
suspend fun fetchDocs() { // Dispatchers.Main
val result = get("https://developer.android.com") // Dispatchers.IO for `get`
show(result) // Dispatchers.Main
}
suspend fun get(url: String) = withContext(Dispatchers.IO) { /* ... */ }
इस उदाहरण में, get()
अब भी मुख्य थ्रेड पर चलता है, लेकिन यह
कोरूटीन शुरू करें. नेटवर्क का अनुरोध करने पर
पूरा हो जाता है, तो get
कॉलबैक का इस्तेमाल करने के बजाय, निलंबित कोरूटीन को फिर से चालू करता है
मुख्य थ्रेड को सूचना दें.
Kotlin में स्टैक फ़्रेम का इस्तेमाल करके यह मैनेज किया जाता है कि कौनसा फ़ंक्शन साथ में चल रहा है का इस्तेमाल करें. कोरूटीन को निलंबित करते समय, मौजूदा स्टैक को कॉपी करके बाद के लिए सेव किया जाता है. फिर से शुरू करते समय, स्टैक फ़्रेम जहां से इसे सेव किया गया था वहीं से कॉपी करने पर, फ़ंक्शन फिर से काम करना शुरू कर देता है. भले ही, कोड किसी सामान्य क्रम में चलने वाले ब्लॉकिंग कोड जैसा दिख सकता है अनुरोध है, तो कोरूटीन यह पक्का करता है कि नेटवर्क अनुरोध, मुख्य थ्रेड.
मुख्य तौर पर सुरक्षा के लिए कोरूटीन इस्तेमाल करना
Kotlin कोरूटीन, डिस्पैचर का इस्तेमाल करके यह तय करते हैं कि कौनसे थ्रेड का इस्तेमाल किया जाए कोरूटीन एक्ज़ीक्यूट होने की सुविधा मौजूद है. कोड को मुख्य थ्रेड के बाहर चलाने के लिए, Kotlin को निर्देश दें कोरूटीन, डिफ़ॉल्ट या IO डिसपैचर पर काम करते हैं. तय सीमा में Kotlin, सभी कोरूटीन, डिस्पैचर में चलने चाहिए. भले ही, वे इस पर चल रहे हों मुख्य थ्रेड. कोरूटीन खुद को निलंबित कर सकते हैं और डिस्पैचर, उन्हें फिर से चलाने की ज़िम्मेदारी भी
यह तय करने के लिए कि कोरूटीन कहां चलने चाहिए, Kotlin तीन डिस्पैचर की सुविधा देती है इन तरीकों का इस्तेमाल किया जा सकता है:
- Dispatchers.Main - इस डिसपैचर का इस्तेमाल मुख्य
Android थ्रेड. इसका इस्तेमाल सिर्फ़ यूज़र इंटरफ़ेस (यूआई) के साथ इंटरैक्ट करने के लिए किया जाना चाहिए और
तेज़ी से काम करने में मदद मिलती है. उदाहरण के लिए,
suspend
फ़ंक्शन को कॉल करना और रन करना Android के यूज़र इंटरफ़ेस (यूआई) फ़्रेमवर्क से जुड़ी कार्रवाइयां और अपडेट करनाLiveData
ऑब्जेक्ट. - Dispatchers.IO - इस डिस्पैचर को डिस्क या नेटवर्क चलाने के लिए ऑप्टिमाइज़ किया गया मुख्य थ्रेड के बाहर I/O. उदाहरण के लिए, रूम कॉम्पोनेंट, फ़ाइलों को पढ़ना या उनमें लिखना, और नेटवर्क से जुड़ी कार्रवाइयां करना.
- Dispatchers.Default - इस डिस्पैचर को कार्रवाई करने के लिए ऑप्टिमाइज़ किया गया है मुख्य थ्रेड के बाहर काम करने के लिए, सीपीयू की ज़रूरत नहीं होती. इस्तेमाल के उदाहरणों में, JSON को पार्स करने और सूची में शामिल करने के बारे में जानकारी.
पिछले उदाहरण में, डिस्पैचर का इस्तेमाल करके
get
फ़ंक्शन का इस्तेमाल करना होगा. get
के मुख्य भाग के अंदर, withContext(Dispatchers.IO)
को कॉल करें
IO थ्रेड पूल पर चलने वाला ब्लॉक बनाना. कोई भी कोड, जिसे आपने
ब्लॉक हमेशा IO
डिस्पैचर के ज़रिए काम करता है. withContext
खुद एक
सस्पेंड फ़ंक्शन, फ़ंक्शन get
एक सस्पेंड फ़ंक्शन भी है.
suspend fun fetchDocs() { // Dispatchers.Main
val result = get("developer.android.com") // Dispatchers.Main
show(result) // Dispatchers.Main
}
suspend fun get(url: String) = // Dispatchers.Main
withContext(Dispatchers.IO) { // Dispatchers.IO (main-safety block)
/* perform network IO here */ // Dispatchers.IO (main-safety block)
} // Dispatchers.Main
}
कोरूटीन की मदद से, ज़्यादा बारीकी से कंट्रोल करके थ्रेड भेजे जा सकते हैं. क्योंकि
withContext()
की मदद से, कोड की किसी भी लाइन के थ्रेड पूल को कंट्रोल किया जा सकता है
कॉलबैक की सुविधा का इस्तेमाल करके, इसे पढ़ने जैसे छोटे फ़ंक्शन पर लागू किया जा सकता है
किसी डेटाबेस से या नेटवर्क के लिए अनुरोध करके. इस्तेमाल करने का बेहतर तरीका
withContext()
ताकि यह पक्का किया जा सके कि हर फ़ंक्शन मुख्य-सुरक्षित है, जिसका मतलब है कि आप
मुख्य थ्रेड से फ़ंक्शन को कॉल कर सकते हैं. इस तरह से, कॉलर को
सोचें कि फ़ंक्शन को चलाने के लिए किस थ्रेड का इस्तेमाल करना चाहिए.
पिछले उदाहरण में, fetchDocs()
मुख्य थ्रेड पर लागू होता है; हालांकि, यह
get
को सुरक्षित रूप से कॉल कर सकता है, जो बैकग्राउंड में नेटवर्क अनुरोध करता है.
ऐसा इसलिए है, क्योंकि कोरूटीन suspend
और resume
के साथ काम करते हैं. इसलिए, कोरूटीन मुख्य पेज पर
withContext
ब्लॉक के होते ही, थ्रेड को get
नतीजे के साथ फिर से शुरू किया जाता है
हो गया.
withContext() की परफ़ॉर्मेंस
withContext()
कॉलबैक-आधारित मिलती-जुलती वैल्यू की तुलना में, ज़्यादा ओवरहेड नहीं जोड़ता है
लागू करना. इसके अलावा, withContext()
कॉल को ऑप्टिमाइज़ किया जा सकता है
लागू करने के बजाय कॉलबैक पर आधारित होता है. इसके लिए
उदाहरण के लिए, अगर कोई फ़ंक्शन किसी नेटवर्क को दस कॉल करता है, तो Kotlin को
आउटर withContext()
का इस्तेमाल करके, सिर्फ़ एक बार थ्रेड स्विच करें. इसके बाद, भले ही
नेटवर्क लाइब्रेरी, withContext()
का इस्तेमाल कई बार करती है, लेकिन यह उसी पर रहती है
और थ्रेड के बीच स्विच करने से बचा जाता है. इसके अलावा, Kotlin में स्विच करने की सुविधा को ऑप्टिमाइज़ किया जाता है
थ्रेड स्विच होने से रोकने के लिए, Dispatchers.Default
से Dispatchers.IO
के बीच
मदद मिलती है.
कोरूटीन शुरू करना
कोरूटीन शुरू करने के लिए, इन दो में से किसी एक तरीके का इस्तेमाल किया जा सकता है:
launch
एक नया कोरूटीन शुरू करता है और कॉलर को नतीजा नहीं दिखाता है. कोई भी ऐसा काम जिसे "फ़ायर ऐंड फ़ाॅरगेट" माना जाता हैlaunch
का इस्तेमाल करके शुरू किया जा सकता है.async
एक नया कोरूटीन शुरू करता है और आपको निलंबन के साथ नतीजा वापस करने की अनुमति देता हैawait
नाम का फ़ंक्शन.
आम तौर पर, आपको किसी सामान्य फ़ंक्शन से, एक नए कोरूटीन को launch
करना चाहिए.
क्योंकि एक सामान्य फ़ंक्शन await
को कॉल नहीं कर सकता. घर के अंदर होने पर ही async
का इस्तेमाल करें
किसी अन्य कोरूटीन या सस्पेंड फ़ंक्शन में होने पर,
समानांतर अपघटन.
पैरलल डिकम्पोज़िशन
suspend
फ़ंक्शन में शुरू होने वाले सभी कोरूटीन तब बंद होने चाहिए, जब
उस फ़ंक्शन का इस्तेमाल करके वैल्यू कैलकुलेट की जाती है. इसलिए, आपको यह गारंटी देनी होगी कि ये कोरूटीन
वापस आने से पहले पूरा कर लें. Kotlin में स्ट्रक्चर्ड कॉनएंसी की मदद से,
एक coroutineScope
जो एक या एक से ज़्यादा कोरूटीन शुरू करता है. इसके बाद, await()
का इस्तेमाल करके
(एक कोरूटीन के लिए) या awaitAll()
(एक से ज़्यादा कोरूटीन के लिए), आपके पास ये काम करने का विकल्प होता है
गारंटी दें कि ये कोरूटीन, फ़ंक्शन से वापस आने से पहले खत्म हो जाते हैं.
उदाहरण के लिए, ऐसे coroutineScope
का इस्तेमाल करें जो दो दस्तावेज़ फ़ेच करता है
एसिंक्रोनस रूप से. हर स्थगित रेफ़रंस पर await()
को कॉल करने पर, हम गारंटी देते हैं
कि दोनों async
कार्रवाइयां, कोई वैल्यू देने से पहले पूरी हो जाती हैं:
suspend fun fetchTwoDocs() =
coroutineScope {
val deferredOne = async { fetchDoc(1) }
val deferredTwo = async { fetchDoc(2) }
deferredOne.await()
deferredTwo.await()
}
आपके पास कलेक्शन के लिए भी awaitAll()
का इस्तेमाल करने का विकल्प है, जैसा कि इस उदाहरण में दिखाया गया है:
suspend fun fetchTwoDocs() = // called on any Dispatcher (any thread, possibly Main)
coroutineScope {
val deferreds = listOf( // fetch two docs at the same time
async { fetchDoc(1) }, // async returns a result for the first doc
async { fetchDoc(2) } // async returns a result for the second doc
)
deferreds.awaitAll() // use awaitAll to wait for both network requests
}
भले ही fetchTwoDocs()
, async
के साथ नए कोरूटीन लॉन्च करता हो, लेकिन फ़ंक्शन
लॉन्च किए गए कोरूटीन के खत्म होने से पहले इंतज़ार करने के लिए, awaitAll()
का इस्तेमाल करता है
वापस आ रहा है. हालांकि, ध्यान दें कि भले ही हमने awaitAll()
को कॉल न किया हो, लेकिन
coroutineScope
बिल्डर, कॉल करने वाले कोरूटीन को फिर से शुरू नहीं करता है
सभी नए कोरूटीन पूरे होने तक fetchTwoDocs
.
इसके अलावा, coroutineScope
उन अपवादों को कैच कर लेता है जिन्हें कोरूटीन फेंकते हैं
और उन्हें वापस कॉलर के पास भेज देता है.
समानांतर अपघटन के बारे में ज़्यादा जानकारी के लिए देखें सस्पेंड करने के फ़ंक्शन को लिखना.
कोरूटीन कॉन्सेप्ट
CoroutineScope
CoroutineScope
launch
या async
का इस्तेमाल करके बनाए गए किसी भी कोरूटीन को ट्रैक करता है. कॉन्टेंट बनाने
चल रहे काम (जैसे, चल रहे कोरूटीन) को कॉल करके रद्द किया जा सकता है
किसी भी समय scope.cancel()
. Android में, कुछ KTX लाइब्रेरी
कुछ लाइफ़साइकल क्लास के लिए, अपना CoroutineScope
. उदाहरण के लिए,
ViewModel
ने
viewModelScope
,
और Lifecycle
में lifecycleScope
है.
हालांकि, डिसपैचर के उलट, CoroutineScope
कोरूटीन नहीं चलता.
viewModelScope
का इस्तेमाल, यहां दिए गए उदाहरणों में भी किया गया है
Android पर कोरूटीन की सुविधा के साथ बैकग्राउंड थ्रेडिंग.
हालांकि, अगर आपको मैन्युअल तरीके से कस्टमाइज़ करने के लिए अपना CoroutineScope
बनाना हो
आपके ऐप्लिकेशन की किसी खास लेयर में कोरूटीन का लाइफ़साइकल, आपके पास एक बनाने का विकल्प है
इस तरह से:
class ExampleClass {
// Job and Dispatcher are combined into a CoroutineContext which
// will be discussed shortly
val scope = CoroutineScope(Job() + Dispatchers.Main)
fun exampleMethod() {
// Starts a new coroutine within the scope
scope.launch {
// New coroutine that can call suspend functions
fetchDocs()
}
}
fun cleanUp() {
// Cancel the scope to cancel ongoing coroutines work
scope.cancel()
}
}
रद्द किए गए स्कोप से ज़्यादा कोरूटीन नहीं बन सकते. इसलिए, आपको
scope.cancel()
को सिर्फ़ तब कॉल करें, जब कोई ऐसी क्लास हो जो इसकी लाइफ़साइकल को कंट्रोल करती है
को खत्म किया जा रहा है. viewModelScope
का इस्तेमाल करते समय,
ViewModel
क्लास रद्द कर देती है
आपके लिए ViewModel के onCleared()
तरीके में अपने-आप स्कोप दिखता है.
काम
Job
कोरूटीन के लिए हैंडल है. launch
की मदद से बनाया गया हर कोरूटीन
या async
, Job
इंस्टेंस की वैल्यू दिखाता है, जो
कोरूटीन है और वह अपनी लाइफ़साइकल को मैनेज करता है. आप Job
को
CoroutineScope
, इसकी लाइफ़साइकल को और मैनेज करता है, जैसा कि यहां दिखाया गया है
उदाहरण:
class ExampleClass {
...
fun exampleMethod() {
// Handle to the coroutine, you can control its lifecycle
val job = scope.launch {
// New coroutine
}
if (...) {
// Cancel the coroutine started above, this doesn't affect the scope
// this coroutine was launched in
job.cancel()
}
}
}
कोरूटीन कॉन्टेक्स्ट
CoroutineContext
एलिमेंट के इन सेट का इस्तेमाल करके, कोरूटीन के व्यवहार को तय करता है:
Job
: कोरूटीन की लाइफ़साइकल को कंट्रोल करता है.CoroutineDispatcher
: डिस्पैच सही थ्रेड पर काम करते हैं.CoroutineName
: कोरूटीन का नाम. इससे डीबग करने में मदद मिलती है.CoroutineExceptionHandler
: ऐसे अपवादों को हैंडल करता है जिनकी पहचान नहीं हो पाई है.
किसी स्कोप में बनाए गए नए कोरूटीन के लिए, नया Job
इंस्टेंस यह है
नए कोरूटीन और दूसरे CoroutineContext
एलिमेंट को असाइन किया जाता है
इन्हें मौजूदा स्कोप से इनहेरिट किया जाता है. इनहेरिट की गई सेटिंग को बदला जा सकता है
launch
या async
में नया CoroutineContext
पास करके एलिमेंट
फ़ंक्शन का इस्तेमाल करना होगा. ध्यान दें कि Job
को launch
या async
पर पास करने से कोई असर नहीं पड़ता,
क्योंकि Job
का नया इंस्टेंस, हमेशा एक नए कोरूटीन को असाइन किया जाता है.
class ExampleClass {
val scope = CoroutineScope(Job() + Dispatchers.Main)
fun exampleMethod() {
// Starts a new coroutine on Dispatchers.Main as it's the scope's default
val job1 = scope.launch {
// New coroutine with CoroutineName = "coroutine" (default)
}
// Starts a new coroutine on Dispatchers.Default
val job2 = scope.launch(Dispatchers.Default + CoroutineName("BackgroundCoroutine")) {
// New coroutine with CoroutineName = "BackgroundCoroutine" (overridden)
}
}
}
कोरूटीन के अतिरिक्त संसाधन
कोरूटीन से जुड़े और संसाधनों के लिए, ये लिंक देखें: