StateFlow
और SharedFlow
, फ़्लो एपीआई हैं. इनकी मदद से, फ़्लो में स्टेटस अपडेट को बेहतर तरीके से भेजा जा सकता है. साथ ही, एक से ज़्यादा उपभोक्ताओं को वैल्यू भेजी जा सकती है.
StateFlow
StateFlow
स्टेटर की निगरानी वाला ऐसा फ़्लो है जो अपने कलेक्टर को मौजूदा और नए राज्य अपडेट देता है. मौजूदा स्थिति की वैल्यू को, value
प्रॉपर्टी से भी पढ़ा जा सकता है. स्टेटस को अपडेट करने और उसे फ़्लो में भेजने के लिए, MutableStateFlow
क्लास की value
प्रॉपर्टी को नई वैल्यू असाइन करें.
Android में, StateFlow
उन क्लास के लिए बिलकुल सही है
जिनके लिए मॉनिटर किए जा सकने वाले म्यूट किए जा सकने वाले स्टेटस को बनाए रखना ज़रूरी होता है.
Kotlin फ़्लो के उदाहरणों का पालन करके, StateFlow
को LatestNewsViewModel
से एक्सपोज़ किया जा सकता है, ताकि View
, यूज़र इंटरफ़ेस (यूआई) की स्थिति के अपडेट को सुन सके और कॉन्फ़िगरेशन में बदलाव होने पर भी स्क्रीन की स्थिति को बनाए रख सके.
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
// Backing property to avoid state updates from other classes
private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
// The UI collects from this StateFlow to get its state updates
val uiState: StateFlow<LatestNewsUiState> = _uiState
init {
viewModelScope.launch {
newsRepository.favoriteLatestNews
// Update View with the latest favorite news
// Writes to the value property of MutableStateFlow,
// adding a new element to the flow and updating all
// of its collectors
.collect { favoriteNews ->
_uiState.value = LatestNewsUiState.Success(favoriteNews)
}
}
}
}
// Represents different states for the LatestNews screen
sealed class LatestNewsUiState {
data class Success(val news: List<ArticleHeadline>): LatestNewsUiState()
data class Error(val exception: Throwable): LatestNewsUiState()
}
MutableStateFlow
को अपडेट करने की ज़िम्मेदारी, प्रोड्यूसर की होती है. साथ ही, StateFlow
से डेटा इकट्ठा करने वाली सभी क्लास, कंज्यूमर होती हैं. flow
बिल्डर का इस्तेमाल करके बनाए गए कोल्ड फ़्लो के उलट, StateFlow
हॉट होता है: फ़्लो से डेटा इकट्ठा करने पर कोई प्रोड्यूसर कोड ट्रिगर नहीं होता. StateFlow
हमेशा चालू और मेमोरी में रहता है. यह सिर्फ़ तब गैर-ज़रूरी डेटा इकट्ठा करने की प्रोसेस के लिए उपलब्ध होता है, जब गैर-ज़रूरी डेटा इकट्ठा करने की प्रोसेस के रूट से इसका कोई दूसरा रेफ़रंस न हो.
जब कोई नया कंज्यूमर फ़्लो से डेटा इकट्ठा करना शुरू करता है, तो उसे स्ट्रीम की आखिरी स्थिति और उसके बाद की सभी स्थितियां मिलती हैं. आपको यह व्यवहार, LiveData
जैसी अन्य क्लास में भी दिख सकता है.
View
अन्य फ़्लो की तरह ही, StateFlow
को सुनता है:
class LatestNewsActivity : AppCompatActivity() {
private val latestNewsViewModel = // getViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
...
// Start a coroutine in the lifecycle scope
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.
repeatOnLifecycle(Lifecycle.State.STARTED) {
// Trigger the flow and start listening for values.
// Note that this happens when lifecycle is STARTED and stops
// collecting when the lifecycle is STOPPED
latestNewsViewModel.uiState.collect { uiState ->
// New value received
when (uiState) {
is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception)
}
}
}
}
}
}
किसी भी फ़्लो को StateFlow
में बदलने के लिए, इंटरमीडिएट ऑपरेटर stateIn
का इस्तेमाल करें.
StateFlow, फ़्लो, और LiveData
StateFlow
और LiveData
में एक जैसी चीज़ें हैं. दोनों, डेटा होल्डर क्लास हैं और ऐप्लिकेशन के आर्किटेक्चर में इस्तेमाल किए जाने पर, दोनों एक जैसे पैटर्न का पालन करती हैं.
हालांकि, ध्यान दें कि StateFlow
और
LiveData
अलग-अलग तरीके से काम करते हैं:
StateFlow
के लिए, कंस्ट्रक्टर में शुरुआती स्थिति को पास करना ज़रूरी है, जबकिLiveData
के लिए ऐसा करना ज़रूरी नहीं है.- व्यू के
STOPPED
राज्य में जाने पर,LiveData.observe()
उसका रजिस्ट्रेशन अपने-आप रद्द कर देता है. वहीं,StateFlow
या किसी अन्य फ़्लो से डेटा इकट्ठा करना अपने-आप बंद नहीं होता. वही व्यवहार पाने के लिए, आपकोLifecycle.repeatOnLifecycle
ब्लॉक से फ़्लो इकट्ठा करना होगा.
shareIn
का इस्तेमाल करके कोल्ड फ़्लो को गर्म करना
StateFlow
एक हॉट फ़्लो है—यह तब तक मेमोरी में बना रहता है, जब तक फ़्लो इकट्ठा किया जाता है या जब तक इसका कोई अन्य रेफ़रंस, कूड़े के कलेक्शन के रूट से मौजूद होता है. shareIn
ऑपरेटर का इस्तेमाल करके, कोल्ड फ़्लो को हॉट फ़्लो में बदला जा सकता है.
उदाहरण के लिए, Kotlin फ़्लो में बनाए गए callbackFlow
का इस्तेमाल करके, हर कलेक्टर के लिए नया फ़्लो बनाने के बजाय, shareIn
का इस्तेमाल करके Firestore से इकट्ठा किए गए डेटा को कलेक्टर के बीच शेयर किया जा सकता है.
आपको इन परीक्षाओं में पास होना होगा:
CoroutineScope
, जिसका इस्तेमाल फ़्लो शेयर करने के लिए किया जाता है. यह दायरा किसी भी उपभोक्ता की तुलना में ज़्यादा समय तक चल सकता है, ताकि हम शेयर किए जा रहे डेटा को लंबे समय तक इस्तेमाल कर सकें.- हर नए कलेक्टर को फिर से चलाने के लिए आइटम की संख्या.
- सेशन शुरू होने के व्यवहार से जुड़ी नीति.
class NewsRemoteDataSource(...,
private val externalScope: CoroutineScope,
) {
val latestNews: Flow<List<ArticleHeadline>> = flow {
...
}.shareIn(
externalScope,
replay = 1,
started = SharingStarted.WhileSubscribed()
)
}
इस उदाहरण में, latestNews
फ़्लो तब तक चालू रहता है, जब तक externalScope
के साथ कलेक्टर मौजूद रहता है. SharingStarted.WhileSubscribed()
शुरू करने की नीति, अपस्ट्रीम प्रॉड्यूसर को तब तक चालू रखती है, जब तक उसके चैनल पर सदस्य मौजूद हों. शुरू करने के लिए, अन्य नीतियां भी उपलब्ध हैं. जैसे, SharingStarted.Eagerly
प्रोड्यूसर को तुरंत शुरू करने के लिए या
SharingStarted.Lazily
पहला सदस्य जुड़ने के बाद शेयर करना शुरू करने के लिए और फ़्लो को हमेशा चालू रखना.
शेयर किया गयाफ़्लो
shareIn
फ़ंक्शन से SharedFlow
मिलता है, जो एक हॉट फ़्लो है. यह उन सभी कंज्यूमर को वैल्यू भेजता है जो इससे डेटा इकट्ठा करते हैं. SharedFlow
, StateFlow
का एक ऐसा वर्शन है जिसे ज़्यादातर मामलों में इस्तेमाल किया जा सकता है और जिसे आसानी से कॉन्फ़िगर किया जा सकता है.
shareIn
का इस्तेमाल किए बिना भी SharedFlow
बनाया जा सकता है. उदाहरण के लिए, SharedFlow
का इस्तेमाल करके, ऐप्लिकेशन के बाकी हिस्सों को टिक भेजा जा सकता है, ताकि पूरा कॉन्टेंट एक ही समय पर समय-समय पर रीफ़्रेश हो जाए. उपयोगकर्ता के लिए, सबसे नई खबरें फ़ेच करने के अलावा, उसके पसंदीदा विषयों के कलेक्शन के साथ उपयोगकर्ता की जानकारी वाले सेक्शन को भी रीफ़्रेश किया जा सकता है. नीचे दिए गए कोड स्निपेट में, TickHandler
एक SharedFlow
को दिखाता है, ताकि अन्य क्लास को यह पता रहे कि कॉन्टेंट को कब रीफ़्रेश करना है. StateFlow
की तरह ही, किसी क्लास में MutableSharedFlow
टाइप की बैकिंग प्रॉपर्टी का इस्तेमाल करके, आइटम को फ़्लो में भेजें:
// Class that centralizes when the content of the app needs to be refreshed
class TickHandler(
private val externalScope: CoroutineScope,
private val tickIntervalMs: Long = 5000
) {
// Backing property to avoid flow emissions from other classes
private val _tickFlow = MutableSharedFlow<Unit>(replay = 0)
val tickFlow: SharedFlow<Event<String>> = _tickFlow
init {
externalScope.launch {
while(true) {
_tickFlow.emit(Unit)
delay(tickIntervalMs)
}
}
}
}
class NewsRepository(
...,
private val tickHandler: TickHandler,
private val externalScope: CoroutineScope
) {
init {
externalScope.launch {
// Listen for tick updates
tickHandler.tickFlow.collect {
refreshLatestNews()
}
}
}
suspend fun refreshLatestNews() { ... }
...
}
SharedFlow
के काम करने के तरीके को पसंद के मुताबिक बनाने के लिए, ये तरीके अपनाएं:
replay
की मदद से, नए सदस्यों के लिए पहले से जनरेट की गई वैल्यू फिर से भेजी जा सकती हैं.onBufferOverflow
की मदद से, आपको यह तय करने की सुविधा मिलती है कि बफ़र, भेजे जाने वाले आइटम से पूरा भरा हुआ है या नहीं. डिफ़ॉल्ट वैल्यूBufferOverflow.SUSPEND
है, जिससे कॉलर को निलंबित कर दिया जाता है. अन्य विकल्पDROP_LATEST
याDROP_OLDEST
हैं.
MutableSharedFlow
में एक subscriptionCount
प्रॉपर्टी भी होती है, जिसमें कलेक्टर की संख्या मौजूद होती है, ताकि आप अपने कारोबार के लॉजिक को उसी हिसाब से ऑप्टिमाइज़ कर सकें. अगर आपको फ़्लो में भेजी गई नई जानकारी को फिर से नहीं चलाना है, तो MutableSharedFlow
में resetReplayCache
फ़ंक्शन भी शामिल होता है.
फ़्लो के बारे में अन्य संसाधन
- Kotlin की सुविधा Android पर उपलब्ध है
- Android पर Kotlin फ़्लो की जांच करना
- फ़्लो के shareIn और stateIn ऑपरेटर के बारे में ज़रूरी बातें
- LiveData से Kotlin Flow पर माइग्रेट करना
- Kotlin कोरुटिन और फ़्लो के लिए अन्य संसाधन