Android पर Kotlin कोरूटीन

कोरूटीन एक ऐसा डिज़ाइन पैटर्न है जिसे कई चीज़ों के साथ इस्तेमाल किया जा सकता है. Android, एसिंक्रोनस रूप से एक्ज़ीक्यूट होने वाले कोड को आसान बनाने के लिए काम करता है. कोरूटीन जिन्हें वर्शन 1.3 में Kotlin में जोड़ा गया था. साथ ही, इन्हें जानने के लिए भी किया जा सकता है.

Android पर, कोरूटीन लंबे समय तक चलने वाले उन टास्क को मैनेज करने में मदद करते हैं जो ऐसा न हो, तो मुख्य थ्रेड को ब्लॉक करें और ऐप्लिकेशन का इस्तेमाल बंद कर दें. कोरूटीन इस्तेमाल करने वाले 50% से ज़्यादा पेशेवर डेवलपर ने अपनी उत्पादकता बढ़ाई. इस विषय में बताया गया है कि इन समस्याओं को ठीक करने के लिए, Kotlin कोरूटीन का इस्तेमाल कैसे किया जा सकता है की समस्या देता है, जिससे आप ज़्यादा साफ़ और कम शब्दों वाला ऐप्लिकेशन कोड लिख सकते हैं.

सुविधाएं

एसिंक्रोनस प्रोग्रामिंग के लिए, कोरूटीन हमारा सुझाव है: Android. ध्यान देने लायक सुविधाओं में ये शामिल हैं:

  • लाइटवेट: एक ही थ्रेड पर कई कोरूटीन चलाए जा सकते हैं, क्योंकि के लिए सहायता निलंबन, जो उस थ्रेड को ब्लॉक नहीं करता जहां कोरूटीन चल रहा है. निलंबित यह एक साथ कई कार्रवाइयां करने के साथ-साथ, ब्लॉक करने की तुलना में मेमोरी सेव करता है.
  • कम मेमोरी लीक: इसका इस्तेमाल करें स्ट्रक्चर्ड एक साथ कई काम करना स्कोप के अंदर कार्रवाइयां करने के लिए.
  • रद्द करने की पहले से मौजूद सहायता: रद्द करने की प्रोसेस यह प्रोसेस, कोरूटीन की मौजूदा हैरारकी की मदद से अपने-आप लागू होती है.
  • Jetpack इंटिग्रेशन: कई Jetpack लाइब्रेरी में ऐसे एक्सटेंशन जो कोरूटीन के साथ काम करते हैं. कुछ सूचनाएं मिल रही हैं लाइब्रेरी में अलग-अलग कोरूटीन स्कोप में एक्सपोर्ट किया जा सकता है, एक साथ कई काम करने के लिए इस्तेमाल किया जाता है.

उदाहरण के तौर पर दी गई खास जानकारी

ऐप्लिकेशन के आर्किटेक्चर की गाइड के आधार पर, दिए गए उदाहरण इस विषय में नेटवर्क के लिए अनुरोध करके, नतीजे को मुख्य साइट पर वापस भेजना थ्रेड जिसमें ऐप्लिकेशन उपयोगकर्ता को नतीजा दिखा सकता है.

खास तौर पर, ViewModel आर्किटेक्चर कॉम्पोनेंट, मुख्य थ्रेड पर रिपॉज़िटरी लेयर को कॉल करता है नेटवर्क अनुरोध को ट्रिगर कर सकता है. यह गाइड अलग-अलग तरह के समाधान के बारे में बताती है जो मुख्य थ्रेड को अनब्लॉक करने के लिए कोरूटीन का इस्तेमाल करती हैं.

ViewModel में KTX एक्सटेंशन का एक सेट शामिल है जो सीधे तौर पर इनके साथ काम करता है कोरूटीन. ये एक्सटेंशन lifecycle-viewmodel-ktx लाइब्रेरी और इसे इस्तेमाल किया गया है देखें.

डिपेंडेंसी की जानकारी

अपने Android प्रोजेक्ट में कोरूटीन इस्तेमाल करने के लिए, ये डिपेंडेंसी जोड़ें ऐप्लिकेशन की build.gradle फ़ाइल में:

ग्रूवी

dependencies {
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
}

Kotlin

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
}

बैकग्राउंड थ्रेड में एक्ज़ीक्यूट किया जा रहा है

मुख्य थ्रेड पर नेटवर्क अनुरोध करने पर, इंतज़ार करना पड़ सकता है या ब्लॉक किया जा सकता है. जब तक उसे कोई प्रतिक्रिया न मिल जाए. थ्रेड को ब्लॉक करने की वजह से, ओएस काम नहीं कर रहा है onDraw() को कॉल कर पाएगा. इससे आपका ऐप्लिकेशन फ़्रीज़ हो सकता है और हो सकता है ऐप्लिकेशन नॉट रिस्पॉन्डिंग (ANR) डायलॉग पर ले जाता है. बेहतर उपयोगकर्ता के लिए अनुभव है, तो आइए इस कार्रवाई को बैकग्राउंड थ्रेड पर चलाते हैं.

आइए, सबसे पहले Repository की हमारी क्लास देखते हैं और जानते हैं कि यह कैसा है नेटवर्क के लिए अनुरोध किया जा रहा है:

sealed class Result<out R> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
}

class LoginRepository(private val responseParser: LoginResponseParser) {
    private const val loginUrl = "https://example.com/login"

    // Function that makes the network request, blocking the current thread
    fun makeLoginRequest(
        jsonBody: String
    ): Result<LoginResponse> {
        val url = URL(loginUrl)
        (url.openConnection() as? HttpURLConnection)?.run {
            requestMethod = "POST"
            setRequestProperty("Content-Type", "application/json; utf-8")
            setRequestProperty("Accept", "application/json")
            doOutput = true
            outputStream.write(jsonBody.toByteArray())
            return Result.Success(responseParser.parse(inputStream))
        }
        return Result.Error(Exception("Cannot open HttpURLConnection"))
    }
}

makeLoginRequest सिंक्रोनस है और कॉल थ्रेड को ब्लॉक करता है. मॉडल को नेटवर्क अनुरोध की प्रतिक्रिया के बाद, हमारी अपनी Result क्लास है.

जब उपयोगकर्ता क्लिक करता है, तब ViewModel नेटवर्क अनुरोध ट्रिगर करता है उदाहरण के लिए, किसी बटन पर:

class LoginViewModel(
    private val loginRepository: LoginRepository
): ViewModel() {

    fun login(username: String, token: String) {
        val jsonBody = "{ username: \"$username\", token: \"$token\"}"
        loginRepository.makeLoginRequest(jsonBody)
    }
}

पिछले कोड का इस्तेमाल करके, LoginViewModel यूज़र इंटरफ़ेस (यूआई) थ्रेड को ब्लॉक कर रहा है, जब नेटवर्क अनुरोध कर रहा है. निष्पादन को स्थानांतरित करने का सबसे आसान समाधान मुख्य थ्रेड को बंद किया जाता है. यह एक नया कोरूटीन बनाना और नेटवर्क को एक्ज़ीक्यूट करना होता है I/O थ्रेड के लिए अनुरोध:

class LoginViewModel(
    private val loginRepository: LoginRepository
): ViewModel() {

    fun login(username: String, token: String) {
        // Create a new coroutine to move the execution off the UI thread
        viewModelScope.launch(Dispatchers.IO) {
            val jsonBody = "{ username: \"$username\", token: \"$token\"}"
            loginRepository.makeLoginRequest(jsonBody)
        }
    }
}

आइए, login फ़ंक्शन में कोरूटीन कोड को देखते हैं:

  • viewModelScope, पहले से तय CoroutineScope है, जो इसके साथ शामिल है ViewModel KTX एक्सटेंशन. ध्यान दें कि सभी कोरूटीन दायरा. CoroutineScope, एक या इससे ज़्यादा कोरूटीन मैनेज करता है.
  • launch एक ऐसा फ़ंक्शन है जो कोरूटीन बनाता है और संबंधित डिस्पैचर को उसके फ़ंक्शन को एक्ज़ीक्यूट करना.
  • Dispatchers.IO बताता है कि इस कोरूटीन को I/O कार्रवाइयों के लिए रिज़र्व किया गया थ्रेड.

login फ़ंक्शन को इस तरह से एक्ज़ीक्यूट किया जाता है:

  • ऐप्लिकेशन, मुख्य थ्रेड पर मौजूद View लेयर से login फ़ंक्शन को कॉल करता है.
  • launch एक नया कोरूटीन बनाता है और नेटवर्क के लिए अनुरोध करता है स्वतंत्र रूप से I/O कार्रवाइयों के लिए रिज़र्व किए गए थ्रेड पर.
  • कोरूटीन चलने के दौरान, login फ़ंक्शन एक्ज़ीक्यूशन करता रहता है और शायद वापस भेज दिया जाए. ध्यान दें कि आसानी के लिए, नेटवर्क रिस्पॉन्स को फ़िलहाल अनदेखा कर दिया जाता है.

इस कोरूटीन को viewModelScope से शुरू किया गया है. इसलिए, इसे ViewModel का स्कोप. अगर ViewModel को बंद कर दिया जाता है, क्योंकि उपयोगकर्ता, स्क्रीन से दूर नेविगेट कर रहा है, viewModelScope अपने-आप रद्द कर दिया जाता है और सभी चल रहे कोरूटीन रद्द कर दिए जाते हैं.

पिछले उदाहरण में एक समस्या यह है कि अगर एक्ज़ीक्यूशन को साफ़ तौर पर बंद करने के लिए makeLoginRequest को याद रखने की ज़रूरत है मुख्य थ्रेड. आइए, देखते हैं कि हम हल करने के लिए, Repository में किस तरह बदलाव कर सकते हैं इस समस्या को हल कर लिया है.

मुख्य तौर पर सुरक्षा के लिए कोरूटीन इस्तेमाल करना

हम फ़ंक्शन को मुख्य तौर पर सुरक्षित मानते हैं. ऐसा तब होता है, जब वह मुख्य थ्रेड. कॉल करने की सुविधा के तौर पर, makeLoginRequest फ़ंक्शन मुख्य तौर पर सुरक्षित नहीं है मुख्य थ्रेड का makeLoginRequest यूज़र इंटरफ़ेस (यूआई) को ब्लॉक करता है. इसका इस्तेमाल करें एक्ज़ीक्यूशन को आगे बढ़ाने के लिए, कोरूटीन लाइब्रेरी से withContext() फ़ंक्शन कोरूटीन को किसी दूसरे थ्रेड में भेजा जाता है:

class LoginRepository(...) {
    ...
    suspend fun makeLoginRequest(
        jsonBody: String
    ): Result<LoginResponse> {

        // Move the execution of the coroutine to the I/O dispatcher
        return withContext(Dispatchers.IO) {
            // Blocking network request code
        }
    }
}

withContext(Dispatchers.IO), कोरूटीन के एक्ज़ीक्यूशन को I/O थ्रेड, जो हमारे कॉलिंग फ़ंक्शन को मुख्य-सुरक्षित बनाता है और यूज़र इंटरफ़ेस (यूआई) को इन कामों के लिए चालू करता है उन्हें अपडेट करें.

makeLoginRequest पर suspend कीवर्ड का निशान भी लगाया गया है. यह कीवर्ड यह Kotlin का तरीका है, जिससे कोरूटीन के अंदर से कॉल किए जाने वाले फ़ंक्शन को लागू किया जाता है.

इस उदाहरण में, कोरूटीन LoginViewModel में बनाया गया है. जब makeLoginRequest, एक्ज़ीक्यूशन को मुख्य थ्रेड से बाहर ले जाता है, तो कोरूटीन को login फ़ंक्शन को अब मुख्य थ्रेड में एक्ज़ीक्यूट किया जा सकता है:

class LoginViewModel(
    private val loginRepository: LoginRepository
): ViewModel() {

    fun login(username: String, token: String) {

        // Create a new coroutine on the UI thread
        viewModelScope.launch {
            val jsonBody = "{ username: \"$username\", token: \"$token\"}"

            // Make the network call and suspend execution until it finishes
            val result = loginRepository.makeLoginRequest(jsonBody)

            // Display result of the network request to the user
            when (result) {
                is Result.Success<LoginResponse> -> // Happy path
                else -> // Show error in UI
            }
        }
    }
}

ध्यान दें कि यहां कोरूटीन की अब भी ज़रूरत है, क्योंकि makeLoginRequest suspend फ़ंक्शन का इस्तेमाल करने के साथ-साथ सभी suspend फ़ंक्शन को एक कोरूटीन.

यह कोड पिछले login उदाहरण से कई मायनों में अलग है:

  • launch, Dispatchers.IO पैरामीटर नहीं लेता है. अगर आपको लालच नहीं चाहिए, तो launch को Dispatcher पास करते हैं, तो यहां से लॉन्च किए गए कोरूटीन viewModelScope मुख्य थ्रेड में चलता है.
  • नेटवर्क अनुरोध के नतीजे को, अब सफलता दिखाने के लिए मैनेज किया जाता है या गड़बड़ी वाला यूज़र इंटरफ़ेस (यूआई) शामिल करें.

लॉगिन फ़ंक्शन अब इस तरह से काम करता है:

  • ऐप्लिकेशन, मुख्य थ्रेड पर मौजूद View लेयर से login() फ़ंक्शन को कॉल करता है.
  • launch, मुख्य थ्रेड पर एक नया कोरूटीन बनाता है और कोरूटीन शुरू हो जाता है लागू करता है.
  • कोरूटीन में, loginRepository.makeLoginRequest() को किया गया कॉल अब withContext तक कोरूटीन को चलाने का काम निलंबित किया जाएगा makeLoginRequest() में ब्लॉक चल रहा है.
  • withContext ब्लॉक पूरा होने के बाद, login() में कोरूटीन फिर से चालू हो जाता है नेटवर्क अनुरोध के नतीजे के साथ मुख्य थ्रेड पर एक्ज़ीक्यूशन करेगा.

हैंडलिंग से जुड़े अपवाद

उन अपवादों को मैनेज करने के लिए जो Repository लेयर थ्रो कर सकता है, Kotlin के अपवादों के लिए पहले से मौजूद सहायता. इस उदाहरण में, हमने try-catch ब्लॉक का इस्तेमाल किया है:

class LoginViewModel(
    private val loginRepository: LoginRepository
): ViewModel() {

    fun login(username: String, token: String) {
        viewModelScope.launch {
            val jsonBody = "{ username: \"$username\", token: \"$token\"}"
            val result = try {
                loginRepository.makeLoginRequest(jsonBody)
            } catch(e: Exception) {
                Result.Error(Exception("Network request failed"))
            }
            when (result) {
                is Result.Success<LoginResponse> -> // Happy path
                else -> // Show error in UI
            }
        }
    }
}

इस उदाहरण में, makeLoginRequest() की ओर से दिया गया कोई भी ऐसा अपवाद कॉल को यूज़र इंटरफ़ेस (यूआई) में किसी गड़बड़ी के तौर पर हैंडल किया जाता है.

कोरूटीन के अतिरिक्त संसाधन

Android पर कोरूटीन के बारे में ज़्यादा जानकारी के लिए, यह देखें Kotlin कोरूटीन की मदद से, ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाएं.

कोरूटीन से जुड़े और संसाधनों के लिए, ये लिंक देखें: