Kotlin कोरूटीन एक एपीआई उपलब्ध कराते हैं. इससे आपको लिखने में मदद मिलती है
एसिंक्रोनस कोड इस्तेमाल नहीं किया जा सकता. Kotlin कोरूटीन की मदद से,
CoroutineScope
इससे आपको यह मैनेज करने में मदद मिलती है कि आपके कोरूटीन कब चलने चाहिए. हर एसिंक्रोनस
ऑपरेशन किसी खास स्कोप के अंदर चलता है.
लाइफ़साइकल की जानकारी वाले कॉम्पोनेंट,
आपके ऐप्लिकेशन में लॉजिकल स्कोप के लिए कोरूटीन की फ़र्स्ट-क्लास सहायता
LiveData
के साथ इंटरऑपरेबिलिटी लेयर.
इस विषय में, लाइफ़साइकल की जानकारी के साथ कोरूटीन इस्तेमाल करने का तरीका बताया गया है
कॉम्पोनेंट.
KTX डिपेंडेंसी जोड़ना
इस विषय में बताए गए बिल्ट-इन कोरूटीन स्कोप, हर मिलते-जुलते कॉम्पोनेंट के लिए, KTX एक्सटेंशन. ज़रूर जोड़ें तो इन स्कोप का इस्तेमाल करते समय, सबसे सही डिपेंडेंसी का इस्तेमाल करें.
ViewModelScope
के लिए, इसका इस्तेमाल करेंandroidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0
या उससे ज़्यादा.LifecycleScope
के लिए, इसका इस्तेमाल करेंandroidx.lifecycle:lifecycle-runtime-ktx:2.4.0
या उससे ज़्यादा.liveData
के लिए, इसका इस्तेमाल करेंandroidx.lifecycle:lifecycle-livedata-ktx:2.4.0
या उससे ज़्यादा.
लाइफ़साइकल की जानकारी वाले कोरूटीन स्कोप
लाइफ़साइकल की जानकारी वाले कॉम्पोनेंट, यहां दिए गए पहले से मौजूद स्कोप तय करते हैं. इनका इस्तेमाल किया जा सकता है आपके ऐप्लिकेशन में.
ViewModelScope
हर एक के लिए ViewModelScope
तय किया गया है
आपके ऐप्लिकेशन में ViewModel
. कोई भी
इस स्कोप में लॉन्च किया गया कोरूटीन अपने-आप रद्द हो जाता है. ऐसा तब होता है, जब ViewModel
मिटा दिया जाता है. कोरूटीन तब काम आते हैं, जब आपके पास काम है
सिर्फ़ तब किया जाता है, जब ViewModel
चालू हो. उदाहरण के लिए, यदि आप
डेटा लेआउट के लिए, आपको काम का दायरा ViewModel
तक करना चाहिए, ताकि अगर
ViewModel
को हटा दिया गया है. इस्तेमाल से बचने के लिए, काम अपने-आप रद्द हो जाएगा
संसाधन.
ViewModel
के CoroutineScope
को ऐक्सेस करने के लिए, यहां जाएं:
ViewModel की viewModelScope
प्रॉपर्टी, जैसा कि इस उदाहरण में दिखाया गया है:
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
लाइफ़साइकल स्कोप
हर एक के लिए LifecycleScope
तय किया गया है
Lifecycle
ऑब्जेक्ट. कोई भी कोरूटीन
Lifecycle
के खत्म होने पर, इस स्कोप में लॉन्च किया गया कैंपेन रद्द हो जाएगा. आप
इसके ज़रिए Lifecycle
के CoroutineScope
को ऐक्सेस करें:
lifecycle.coroutineScope
या lifecycleOwner.lifecycleScope
प्रॉपर्टी.
नीचे दिए गए उदाहरण में, इन कामों के लिए lifecycleOwner.lifecycleScope
का इस्तेमाल करने का तरीका बताया गया है
एसिंक्रोनस तरीके से प्रीकंप्यूट किया गया टेक्स्ट बनाएं:
class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
val params = TextViewCompat.getTextMetricsParams(textView)
val precomputedText = withContext(Dispatchers.Default) {
PrecomputedTextCompat.create(longTextContent, params)
}
TextViewCompat.setPrecomputedText(textView, precomputedText)
}
}
}
रीस्टार्ट किए जा सकने वाले लाइफ़साइकल के बारे में जानकारी देने वाले कोरूटीन
हालांकि, lifecycleScope
में सदस्यता को रद्द करने का सही तरीका होता है
Lifecycle
के DESTROYED
होने पर, लंबे समय तक अपने-आप चलने वाली कार्रवाइयां,
आपके पास ऐसे अन्य मामले भी हो सकते हैं जहां आपको कोड को एक्ज़ीक्यूट करना है
Lifecycle
के किसी खास स्थिति में होने पर ब्लॉक करें और जब वे इस स्थिति में हों, तो रद्द कर दें
किसी और राज्य में. उदाहरण के लिए, हो सकता है कि आप किसी फ़्लो को तब इकट्ठा करना चाहें, जब
Lifecycle
, STARTED
हैं और STOPPED
होने पर कलेक्शन रद्द करें. यह
अप्रोच से, फ़्लो से होने वाले उत्सर्जन का डेटा सिर्फ़ तब प्रोसेस किया जाता है, जब स्क्रीन पर यूज़र इंटरफ़ेस (यूआई) दिख रहा हो.
और ऐप्लिकेशन के क्रैश होने से बचा जा सकता है.
ऐसे मामलों में, Lifecycle
और LifecycleOwner
निलंबन की वजह बताते हैं
repeatOnLifecycle
एपीआई जो बिलकुल यही काम करता है. नीचे दिए गए उदाहरण में
यह कोड ब्लॉक तब ट्रिगर होता है, जब इससे जुड़ा Lifecycle
कम से कम
STARTED
के स्टेटस के तहत, Lifecycle
के STOPPED
होने पर सदस्यता रद्द हो जाएगी:
class MyFragment : Fragment() {
val viewModel: MyViewModel by viewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Create a new coroutine in the lifecycleScope
viewLifecycleOwner.lifecycleScope.launch {
// repeatOnLifecycle launches the block in a new coroutine every time the
// lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
// Trigger the flow and start listening for values.
// This happens when lifecycle is STARTED and stops
// collecting when the lifecycle is STOPPED
viewModel.someDataFlow.collect {
// Process item
}
}
}
}
}
लाइफ़साइकल की जानकारी वाला फ़्लो कलेक्शन
अगर आपको सिर्फ़ एक फ़्लो पर लाइफ़साइकल की जानकारी वाला कलेक्शन करना है, तो
का इस्तेमाल करें
Flow.flowWithLifecycle()
इस तरीके का इस्तेमाल करके अपने कोड को आसान बना सकते हैं:
viewLifecycleOwner.lifecycleScope.launch {
exampleProvider.exampleFlow()
.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED)
.collect {
// Process the value.
}
}
हालांकि, अगर आपको कई फ़्लो पर लाइफ़साइकल की जानकारी वाला डेटा कलेक्शन करना है,
साथ-साथ, तो आपको हर फ़्लो को अलग-अलग कोरूटीन में इकट्ठा करना होगा. ऐसी स्थिति में,
तो repeatOnLifecycle()
का सीधे इस्तेमाल करना ज़्यादा फ़ायदेमंद होगा:
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
// Because collect is a suspend function, if you want to
// collect multiple flows in parallel, you need to do so in
// different coroutines.
launch {
flow1.collect { /* Process the value. */ }
}
launch {
flow2.collect { /* Process the value. */ }
}
}
}
लाइफ़साइकल के बारे में जानकारी वाले कोरूटीन निलंबित करें
हालांकि, CoroutineScope
में सदस्यता को रद्द करने का सही तरीका होता है
लंबे समय तक अपने-आप चलने वाले ऑपरेशन का इस्तेमाल करता है, तो हो सकता है कि कुछ मामलों में आपको
कोड ब्लॉक का निष्पादन निलंबित करने के लिए, जब तक Lifecycle
राज्य. उदाहरण के लिए, FragmentTransaction
चलाने के लिए, आपको
Lifecycle
कम से कम STARTED
है. ऐसे मामलों में, Lifecycle
की ओर से
अतिरिक्त तरीके: lifecycle.whenCreated
, lifecycle.whenStarted
, और
lifecycle.whenResumed
. इन ब्लॉक के अंदर चलने वाले किसी भी कोरूटीन को निलंबित कर दिया जाता है, अगर
Lifecycle
ज़रूरत के मुताबिक नहीं है.
यहां दिए गए उदाहरण में एक कोड ब्लॉक शामिल है. यह कोड ब्लॉक सिर्फ़ तभी काम करता है, जब
Lifecycle
कम से कम STARTED
स्थिति में है:
class MyFragment: Fragment {
init { // Notice that we can safely launch in the constructor of the Fragment.
lifecycleScope.launch {
whenStarted {
// The block inside will run only when Lifecycle is at least STARTED.
// It will start executing when fragment is started and
// can call other suspend methods.
loadingView.visibility = View.VISIBLE
val canAccess = withContext(Dispatchers.IO) {
checkUserAccess()
}
// When checkUserAccess returns, the next line is automatically
// suspended if the Lifecycle is not *at least* STARTED.
// We could safely run fragment transactions because we know the
// code won't run unless the lifecycle is at least STARTED.
loadingView.visibility = View.GONE
if (canAccess == false) {
findNavController().popBackStack()
} else {
showContent()
}
}
// This line runs only after the whenStarted block above has completed.
}
}
}
अगर कोरूटीन चालू होने के दौरान, Lifecycle
को खत्म हो जाता है, तो
when
तरीकों का इस्तेमाल करने पर, कोरूटीन अपने-आप रद्द हो जाता है. नीचे दिए गए उदाहरण में,
Lifecycle
की स्थिति DESTROYED
होने पर finally
ब्लॉक चलेगा:
class MyFragment: Fragment {
init {
lifecycleScope.launchWhenStarted {
try {
// Call some suspend functions.
} finally {
// This line might execute after Lifecycle is DESTROYED.
if (lifecycle.state >= STARTED) {
// Here, since we've checked, it is safe to run any
// Fragment transactions.
}
}
}
}
}
LiveData के साथ कोरूटीन इस्तेमाल करना
LiveData
का इस्तेमाल करते समय, आपको इन चीज़ों की ज़रूरत पड़ सकती है
का इस्तेमाल, एसिंक्रोनस तरीके से वैल्यू को कैलकुलेट करने के लिए किया जाता है. उदाहरण के लिए, हो सकता है कि आप
और उन्हें आपके यूज़र इंटरफ़ेस (यूआई) पर पेश करने के लिए किया जा सकता है. तय सीमा में
इन मामलों में, liveData
बिल्डर फ़ंक्शन का इस्तेमाल करके, suspend
को कॉल किया जा सकता है
फ़ंक्शन का इस्तेमाल करके, नतीजे को LiveData
ऑब्जेक्ट के तौर पर दिखाते हैं.
नीचे दिए गए उदाहरण में, loadUser()
एक सस्पेंड फ़ंक्शन है, जिसका एलान कहीं और किया गया है. इस्तेमाल की जाने वाली चीज़ें
liveData
बिल्डर फ़ंक्शन का इस्तेमाल करके, loadUser()
को एसिंक्रोनस रूप से कॉल किया जा सकता है. इसके बाद
यह नतीजा देने के लिए, emit()
का इस्तेमाल करें:
val user: LiveData<User> = liveData {
val data = database.loadUser() // loadUser is a suspend function.
emit(data)
}
liveData
बिल्डिंग ब्लॉक
स्ट्रक्चर्ड कॉनकरेंसी प्रिमिटिव
कोरूटीन और LiveData
के बीच होता है. कोड ब्लॉक तब काम करना शुरू करता है, जब
डिवाइस को कॉन्फ़िगर करने के बाद, LiveData
चालू हो जाता है और अपने-आप रद्द हो जाता है
LiveData
के इनऐक्टिव होने पर, टाइम आउट हो जाता है. अगर इसे पहले रद्द किया जाता है
पूरा हो गया है, तो LiveData
के फिर से चालू होने पर वह रीस्टार्ट हो जाता है. अगर यह
पूरा हुआ हो, तो यह रीस्टार्ट नहीं होता. ध्यान दें कि
अपने-आप रद्द होने पर ही रीस्टार्ट होगा. अगर ब्लॉक को किसी दूसरी कंपनी के लिए रद्द किया जाता है
वजह है (उदाहरण के लिए, CancellationException
को फेंकना), तो उसे रीस्टार्ट नहीं किया जाता है.
ब्लॉक से एक से ज़्यादा वैल्यू भी बनाई जा सकती हैं. हर emit()
कॉल को निलंबित किया जाएगा
जब तक मुख्य थ्रेड पर LiveData
वैल्यू सेट नहीं हो जाती, तब तक ब्लॉक को लागू करना होगा.
val user: LiveData<Result> = liveData {
emit(Result.loading())
try {
emit(Result.success(fetchUser()))
} catch(ioException: Exception) {
emit(Result.error(ioException))
}
}
liveData
को इनके साथ भी जोड़ा जा सकता है
Transformations
, जैसा कि यहां दिखाया गया है
नीचे दिया गया उदाहरण:
class MyViewModel: ViewModel() {
private val userId: LiveData<String> = MutableLiveData()
val user = userId.switchMap { id ->
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
emit(database.loadUserById(id))
}
}
}
emitSource()
को कॉल करके, LiveData
से कई वैल्यू का उत्सर्जन किया जा सकता है
फ़ंक्शन का इस्तेमाल करें. ध्यान दें कि emit()
को किया गया हर कॉल
या emitSource()
पहले से जोड़े गए सोर्स को हटा देता है.
class UserDao: Dao {
@Query("SELECT * FROM User WHERE id = :id")
fun getUser(id: String): LiveData<User>
}
class MyRepository {
fun getUser(id: String) = liveData<User> {
val disposable = emitSource(
userDao.getUser(id).map {
Result.loading(it)
}
)
try {
val user = webservice.fetchUser(id)
// Stop the previous emission to avoid dispatching the updated user
// as `loading`.
disposable.dispose()
// Update the database.
userDao.insert(user)
// Re-establish the emission with success type.
emitSource(
userDao.getUser(id).map {
Result.success(it)
}
)
} catch(exception: IOException) {
// Any call to `emit` disposes the previous one automatically so we don't
// need to dispose it here as we didn't get an updated value.
emitSource(
userDao.getUser(id).map {
Result.error(exception, it)
}
)
}
}
}
कोरूटीन से जुड़ी ज़्यादा जानकारी के लिए, ये लिंक देखें:
- Kotlin कोरूटीन की मदद से, ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाना
- कोरूटीन की खास जानकारी
- CoroutineWorker में थ्रेडिंग
अन्य संसाधन
लाइफ़साइकल की जानकारी वाले कॉम्पोनेंट के साथ कोरूटीन इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, इन अतिरिक्त संसाधनों को पूरा करें.
सैंपल
ब्लॉग
- Android पर कोरूटीन: ऐप्लिकेशन के पैटर्न
- Android में आसान कोरूटीन: viewModelScope
- कोरूटीन में, लगातार दो LiveData उत्सर्जन का टेस्ट करना
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक टेक्स्ट दिखता है
- LiveData की खास जानकारी
- लाइफ़साइकल-अवेयर कॉम्पोनेंट की मदद से लाइफ़साइकल मैनेज करना
- पेज किया गया डेटा लोड करना और दिखाना