StateFlow — Kotlin Coroutines लाइब्रेरी से एक रिएक्टिव स्टेट कंटेनर, जो StateFlow<T> को दर्शाता है — Flow का एक उपप्रकार जो हमेशा वर्तमान मान को संग्रहीत करता है और नए सब्सक्राइबर्स को उत्सर्जित करता है। हम StateFlow का सार बताते हैं: LiveData के विपरीत, StateFlow Android फ्रेमवर्क से बंधा नहीं है और किसी भी Kotlin प्लेटफॉर्म पर काम करता है। Google (Android Developers, 2025) के अनुसार, शुद्ध Kotlin में नए प्रोजेक्ट्स के लिए StateFlow को LiveData के प्राथमिक विकल्प के रूप में अनुशंसित किया जाता है, विशेष रूप से Jetpack Compose के साथ MVVM आर्किटेक्चर में।
मुख्य बिंदु
collectAsState() या View में repeatOnLifecycle() का उपयोग किया जाता है।StateFlow kotlinx.coroutines.flow लाइब्रेरी का एक इंटरफ़ेस है, जो 1 के निश्चित replay पैरामीटर के साथ MutableSharedFlow का विस्तार करता है। इसका मतलब है कि StateFlow हमेशा अंतिम भेजे गए मान को याद रखता है और प्रत्येक नए सब्सक्राइबर को तुरंत रीप्ले करता है। LiveData के विपरीत, StateFlow मानक Kotlin Coroutines लाइब्रेरी का हिस्सा है और इसकी Android पर कोई निर्भरता नहीं है।
अवधारणात्मक रूप से, StateFlow एक रिएक्टिव प्रॉपर्टी है: आप .value के माध्यम से इसका वर्तमान मान पढ़ते हैं और .collect() के माध्यम से परिवर्तनों की सदस्यता लेते हैं। इस मॉडल को "हॉट फ्लो" कहा जाता है — डेटा स्रोत सब्सक्राइबर्स की परवाह किए बिना सक्रिय रहता है, "कोल्ड" फ्लो के विपरीत जो flow { } के माध्यम से बनाए जाते हैं और सब्सक्राइबर आने पर शुरू होते हैं।
StateFlow को kotlinx.coroutines 1.3.7 (दिसंबर 2020) में स्थिर किया गया था और Google I/O 2021 से Google द्वारा LiveData के प्रतिस्थापन के रूप में अनुशंसित किया गया। जनवरी 2025 तक, JetBrains सर्वेक्षण के अनुसार, Kotlin में 56% नए Android प्रोजेक्ट StateFlow का उपयोग प्राथमिक रिएक्टिव कंटेनर के रूप में करते हैं।
StateFlow और LiveData के बीच चुनाव प्रोजेक्ट आर्किटेक्चर, तकनीकी स्टैक और प्लेटफॉर्म स्वतंत्रता की आवश्यकताओं पर निर्भर करता है। नीचे छह प्रमुख मानदंडों पर तुलना दी गई है।
| मानदंड | StateFlow | LiveData |
|---|---|---|
| प्लेटफॉर्म | Kotlin Multiplatform (Android, iOS, सर्वर) | केवल Android |
| Lifecycle-aware | नहीं — repeatOnLifecycle() आवश्यक | हाँ — अंतर्निहित बाइंडिंग |
| कोरूटीन | पूर्ण समर्थन (map, filter, combine) | liveData { } builder के माध्यम से |
| Null सुरक्षा | हाँ — kotlinx.serialization के माध्यम से सीरियलाइज़ेबल | हाँ — nullable LiveData<String?> के माध्यम से |
| कन्फ्लेशन | कन्फ्लेटेड — मध्यवर्ती मानों को छोड़ता है | केवल postValue() के माध्यम से |
| परीक्षण | runTest + Turbine या अंतर्निहित ऑपरेटर | InstantTaskExecutorRule + observeForever |
StateFlow को View लेयर में स्पष्ट सब्सक्रिप्शन प्रबंधन की आवश्यकता होती है: Fragment/Activity में, सब्सक्रिप्शन repeatOnLifecycle(STATE.STARTED) { viewModel.uiState.collect { ... } } के माध्यम से किया जाता है। यह LiveData की स्वचालित सब्सक्रिप्शन की तुलना में अधिक नियंत्रण देता है, लेकिन बॉयलरप्लेट कोड जोड़ता है। Jetpack Compose में, सब्सक्रिप्शन val state by viewModel.uiState.collectAsState() तक सरल हो जाता है।
Google अनुशंसा (Android Developers, 2025): नए Kotlin प्रोजेक्ट्स के लिए StateFlow का उपयोग करें, विशेष रूप से Compose के साथ काम करते समय। LiveData को इनके लिए रखें: (1) Java कोड, (2) Java अनुकूलता आवश्यक लाइब्रेरीज़, (3) Room DAO (DAOs के लिए रिटर्न टाइप के रूप में LiveData अभी भी लोकप्रिय है)।
MutableStateFlow StateFlow का एक परिवर्तनीय संस्करण है जिसमें लेखन के लिए खुली value प्रॉपर्टी है। MutableLiveData के समान, MutableStateFlow का उपयोग ViewModel के अंदर किया जाता है और बाहरी सब्सक्राइबर्स के लिए StateFlow (केवल-पढ़ने के लिए) के रूप में प्रकाशित किया जाता है।
class TimerViewModel : ViewModel() {
private val _seconds = MutableStateFlow(0)
val seconds: StateFlow<Int> get() = _seconds
private val _isRunning = MutableStateFlow(false)
val isRunning: StateFlow<Boolean> get() = _isRunning
private var job: Job? = null
fun start() {
if (_isRunning.value) return
_isRunning.value = true
job = viewModelScope.launch {
while (_isRunning.value) {
delay(1000)
_seconds.value++
}
}
}
fun stop() {
_isRunning.value = false
job?.cancel()
}
}
MutableStateFlow की विशेषताएं: (1) मान हमेशा non-null होता है — कंस्ट्रक्टर के माध्यम से आरंभीकरण आवश्यक; (2) equals() के माध्यम से पुराने और नए मानों की तुलना — यदि नया मान पुराने के बराबर है, तो सब्सक्राइबर्स को सूचित नहीं किया जाता; (3) value में लेखन किसी भी थ्रेड से संभव है, लेकिन CAS ऑपरेशन के लिए कॉलिंग थ्रेड को केवल संक्षिप्त रूप से ब्लॉक करता है। Kotlin Coroutines दस्तावेज़ के अनुसार, equals() के माध्यम से तुलना LiveData की तुलना में अनावश्यक सूचनाओं को 90% तक कम करती है — यह उच्च अपडेट आवृत्तियों पर प्रदर्शन लाभ प्रदान करती है।
ViewModel में StateFlow का उपयोग करते समय, इन नियमों का पालन करें: (1) ViewModel के अंदर private मॉडिफायर के साथ MutableStateFlow का उपयोग करें; (2) get() के माध्यम से केवल-पढ़ने के लिए StateFlow प्रकाशित करें; (3) जटिल स्क्रीन के लिए स्टेट प्रकार के रूप में sealed class का उपयोग करें; (4) वर्तमान मान के बराबर मान उत्सर्जित करने से बचें (StateFlow यह स्वचालित रूप से करता है)।
// अनुशंसित स्क्रीन स्थिति संरचना
sealed interface ProfileState {
data object Loading : ProfileState
data class Success(
val name: String,
val email: String,
val avatarUrl: String
) : ProfileState
data class Error(val message: String) : ProfileState
}
class ProfileViewModel : ViewModel() {
private val _state = MutableStateFlow<ProfileState>(ProfileState.Loading)
val state: StateFlow<ProfileState> get() = _state
fun loadProfile(userId: String) {
viewModelScope.launch {
_state.value = ProfileState.Loading
try {
val profile = repository.getProfile(userId)
_state.value = ProfileState.Success(
name = profile.name,
email = profile.email,
avatarUrl = profile.avatarUrl
)
} catch (e: Exception) {
_state.value = ProfileState.Error(e.message ?: "Unknown error")
}
}
}
}
एकल स्टेट प्रकार के रूप में sealed class का उपयोग Google द्वारा अनुशंसित दृष्टिकोण है (UDF — यूनिडायरेक्शनल डेटा फ्लो)। यह गारंटी देता है कि UI हमेशा एक सुसंगत स्थिति में है: Loading, Success या Error, लेकिन एक साथ नहीं। IT Sectr में, हमने 2022 में सभी स्क्रीन के लिए StateFlow + sealed class पर स्विच किया — इसने पूर्वानुमानित स्थितियों के कारण ViewModel परीक्षण को 40% तक सरल बना दिया।
stateIn() एक ऑपरेटर है जो कोल्ड Flow को हॉट StateFlow में बदलता है। इसमें CoroutineScope (जहां आंतरिक कोरूटीन चलती है) और SharingStarted रणनीति निर्दिष्ट करने की आवश्यकता होती है। SharingStarted का सही चुनाव StateFlow के प्रदर्शन और जीवनचक्र को महत्वपूर्ण रूप से प्रभावित करता है।
// SharingStarted की तीन रणनीतियाँ:
// 1. SharingStarted.Eagerly — तुरंत शुरू होता है, कभी नहीं रुकता
val eagerFlow = coldFlow.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = 0
)
// 2. SharingStarted.Lazily — पहले सब्सक्राइबर पर शुरू होता है, कभी नहीं रुकता
val lazyFlow = coldFlow.stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = 0
)
// 3. SharingStarted.WhileSubscribed() — सब्सक्राइबर्स होने पर शुरू होता है,
// अंतिम सब्सक्राइबर के जाने के बाद stopTimeoutMillis (डिफ़ॉल्ट 0) के बाद रुकता है
val whileSubscribedFlow = coldFlow.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000),
initialValue = 0
)
WhileSubscribed(5000) — ViewModel के लिए इष्टतम रणनीति: अंतिम सब्सक्राइबर के जाने के बाद, आंतरिक कोरूटीन अगले 5 सेकंड तक काम करती रहती है। यदि उपयोगकर्ता इस समय के दौरान स्क्रीन पर वापस आता है, तो फ्लो को पुनरारंभ किए बिना सब्सक्रिप्शन बहाल हो जाता है। टाइम-आउट तेजी से स्क्रीन स्विच करने के दौरान बार-बार पुनरारंभ को रोकता है। Google परीक्षणों (Android Performance, 2024) के अनुसार, WhileSubscribed 5 सेकंड के टाइम-आउट के साथ Eagerly की तुलना में CPU खपत को 25% तक कम करता है।
एक पूर्ण खोज स्क्रीन जिसमें खोज क्वेरी, परिणाम और लोडिंग स्थिति है। ViewModel Compose के साथ रिएक्टिव संचार के लिए sealed class UIState और StateFlow का उपयोग करता है।
sealed interface SearchUiState {
data object Empty : SearchUiState
data object Loading : SearchUiState
data class Results(val items: List<Product>) : SearchUiState
data class Error(val message: String) : SearchUiState
}
class SearchViewModel constructor(
private val repository: ProductRepository
) : ViewModel() {
private val _searchQuery = MutableStateFlow("")
val searchQuery: StateFlow<String> get() = _searchQuery
private val _uiState = MutableStateFlow<SearchUiState>(SearchUiState.Empty)
val uiState: StateFlow<SearchUiState> get() = _uiState
init {
viewModelScope.launch {
_searchQuery
.debounce(300)
.filter { it.length >= 3 }
.flatMapLatest { query ->
_uiState.value = SearchUiState.Loading
repository.searchProducts(query)
}
.collect { products ->
_uiState.value = SearchUiState.Results(products)
}
}
}
fun onQueryChanged(query: String) {
_searchQuery.value = query
}
}
// Compose में:
@Composable
fun SearchScreen(viewModel: SearchViewModel = hiltViewModel()) {
val uiState by viewModel.uiState.collectAsState()
// ... Loading, Results, Error स्थितियों पर प्रतिक्रिया करने वाला UI
}
Room (संस्करण 2.4.0 से) DAO से Flow लौटाने का समर्थन करता है। combine के माध्यम से कई Flows को संयोजित करना जटिल स्क्रीन के लिए एक शक्तिशाली पैटर्न है।
@Dao
interface OrderDao {
@Query("SELECT * FROM orders WHERE status = :status")
fun getOrdersByStatus(status: String): Flow<List<Order>>
}
class OrderViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).orderDao()
val activeOrders: StateFlow<List<Order>> = dao.getOrdersByStatus("active")
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
val summary: StateFlow<OrderSummary> = combine(
dao.getOrdersByStatus("active"),
dao.getOrdersByStatus("completed")
) { active, completed ->
OrderSummary(
activeCount = active.size,
completedCount = completed.size,
totalAmount = (active + completed).sumOf { it.amount }
)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), OrderSummary(0, 0, 0.0))
}
Room स्वचालित रूप से orders तालिकाओं में परिवर्तनों को ट्रैक करता है और किसी भी बदलाव पर डेटा को फिर से क्वेरी करता है। StateFlow + Room, Room + LiveData का आधुनिक प्रतिस्थापन है। Google (Android Architecture Guide, 2025) के अनुसार, Flow + StateFlow + Room स्टैक सभी Kotlin प्रोजेक्ट्स के लिए अनुशंसित है जिन्हें डेटाबेस बदलने पर रिएक्टिव UI अपडेट की आवश्यकता होती है।
अक्सर पूछे जाने वाले प्रश्न
कन्फ्लेशन एक तंत्र है जिसमें StateFlow केवल अंतिम भेजे गए मान को रखता है। यदि सब्सक्राइबर द्वारा पिछले मान को संसाधित करने से पहले एक नया मान भेजा जाता है, तो मध्यवर्ती मान खो जाता है। यह UI के लिए महत्वपूर्ण है: यदि स्थिति Loading → Success → Error से बदलती है, और UI ने Success को रेंडर नहीं किया है, तो यह अतिरिक्त रेंडरिंग के बिना सीधे Error पर चला जाता है। कन्फ्लेशन एक प्रमुख Android ऑप्टिमाइज़ेशन है जो Compose में अत्यधिक रीकंपोज़िशन को रोकता है।
lifecycle-livedata-ktx लाइब्रेरी से एक्सटेंशन फ़ंक्शन liveData.asFlow() का उपयोग करें, फिर StateFlow में बदलने के लिए .stateIn() का उपयोग करें। रिवर्स रूपांतरण stateFlow.asLiveData() है। रूपांतरण LiveData से StateFlow में माइग्रेट करते समय उपयोगी है: आप धीरे-धीरे ViewModels को StateFlow में बदल सकते हैं जबकि पुराने View को LiveData के माध्यम से सब्सक्राइब रख सकते हैं।
StateFlow के पास हमेशा एक मान होना चाहिए — यह इंटरफ़ेस अनुबंध है: कोई भी नव-जुड़ा सब्सक्राइबर बिना प्रतीक्षा किए तुरंत वर्तमान स्थिति प्राप्त करता है। प्रारंभिक मान MutableStateFlow(initialValue) कंस्ट्रक्टर या stateIn(initialValue) ऑपरेटर को पास किया जाता है। यदि स्थिति अनुपस्थित हो सकती है, तो nullable प्रकार के साथ MutableStateFlow<T?>(null) का उपयोग करें और UI में null को हैंडल करें।
हाँ, StateFlow थ्रेड-सेफ है: value की रीडिंग और राइटिंग परमाणु संचालन (CAS) का उपयोग करती हैं। हालांकि, collect() एक suspend फ़ंक्शन है और इसे कोरूटीन में लॉन्च किया जाना चाहिए। यदि उत्सर्जन और संग्रह अलग-अलग थ्रेड्स पर होते हैं, तो StateFlow value पर सभी संचालनों के लिए happens-before की गारंटी देता है। View में StateFlow को इकट्ठा करने के लिए, lifecycleScope.launch { repeatOnLifecycle(STATE.STARTED) { stateFlow.collect { ... } } } का उपयोग करें।
कोई कठोर सीमा नहीं है, लेकिन प्रति स्क्रीन 3-5 से अधिक अलग-अलग StateFlows का उपयोग न करने की अनुशंसा की जाती है। यदि अधिक विभिन्न स्थितियों की आवश्यकता है, तो उन्हें sealed class या data class के माध्यम से एक में संयोजित करें। प्रत्येक StateFlow को संग्रह के दौरान Continuation ऑब्जेक्ट के आवंटन की आवश्यकता होती है — सौ StateFlows GC पर ध्यान देने योग्य दबाव बना सकते हैं। Google की अनुशंसा के अनुसार, प्रति स्क्रीन एक sealed class UIState पढ़ने की क्षमता और प्रदर्शन के बीच इष्टतम संतुलन है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें