StateFlow — सार, Android में StateFlow vs LiveData

लेखक: IT Sectr प्रकाशित: 2026-02-20 पढ़ने का समय: 9 मिनट

StateFlow — Kotlin Coroutines लाइब्रेरी से एक रिएक्टिव स्टेट कंटेनर, जो StateFlow<T> को दर्शाता है — Flow का एक उपप्रकार जो हमेशा वर्तमान मान को संग्रहीत करता है और नए सब्सक्राइबर्स को उत्सर्जित करता है। हम StateFlow का सार बताते हैं: LiveData के विपरीत, StateFlow Android फ्रेमवर्क से बंधा नहीं है और किसी भी Kotlin प्लेटफॉर्म पर काम करता है। Google (Android Developers, 2025) के अनुसार, शुद्ध Kotlin में नए प्रोजेक्ट्स के लिए StateFlow को LiveData के प्राथमिक विकल्प के रूप में अनुशंसित किया जाता है, विशेष रूप से Jetpack Compose के साथ MVVM आर्किटेक्चर में।

मुख्य बिंदु

  • StateFlow — kotlinx.coroutines.flow से एक स्टेट होल्डर, हमेशा एक वर्तमान मान संग्रहीत करता है और सब्सक्रिप्शन पर इसे उत्सर्जित करता है।
  • MutableStateFlow — mutable value प्रॉपर्टी वाला एक परिवर्तनीय StateFlow, ViewModel के अंदर उपयोग किया जाता है और StateFlow के रूप में प्रकाशित किया जाता है।
  • collect() — परिवर्तनों की सदस्यता के लिए Flow का एक टर्मिनल ऑपरेटर; UI के लिए Compose में collectAsState() या View में repeatOnLifecycle() का उपयोग किया जाता है।
  • StateFlow vs LiveData: StateFlow Lifecycle पर निर्भर नहीं करता, स्पष्ट सब्सक्रिप्शन प्रबंधन की आवश्यकता होती है, लेकिन कोरूटीन और मल्टीप्लेटफॉर्म का समर्थन करता है।
  • stateIn() — किसी भी Flow को SharingStarted रणनीति के साथ StateFlow में बदलने का ऑपरेटर।

Kotlin में StateFlow क्या है?

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 vs LiveData: मुख्य अंतर

StateFlow और LiveData के बीच चुनाव प्रोजेक्ट आर्किटेक्चर, तकनीकी स्टैक और प्लेटफॉर्म स्वतंत्रता की आवश्यकताओं पर निर्भर करता है। नीचे छह प्रमुख मानदंडों पर तुलना दी गई है।

मानदंडStateFlowLiveData
प्लेटफॉर्म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: प्रकाशन और सब्सक्रिप्शन

MutableStateFlow StateFlow का एक परिवर्तनीय संस्करण है जिसमें लेखन के लिए खुली value प्रॉपर्टी है। MutableLiveData के समान, MutableStateFlow का उपयोग ViewModel के अंदर किया जाता है और बाहरी सब्सक्राइबर्स के लिए StateFlow (केवल-पढ़ने के लिए) के रूप में प्रकाशित किया जाता है।

kotlin
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: सर्वोत्तम अभ्यास

ViewModel में StateFlow का उपयोग करते समय, इन नियमों का पालन करें: (1) ViewModel के अंदर private मॉडिफायर के साथ MutableStateFlow का उपयोग करें; (2) get() के माध्यम से केवल-पढ़ने के लिए StateFlow प्रकाशित करें; (3) जटिल स्क्रीन के लिए स्टेट प्रकार के रूप में sealed class का उपयोग करें; (4) वर्तमान मान के बराबर मान उत्सर्जित करने से बचें (StateFlow यह स्वचालित रूप से करता है)।

kotlin
// अनुशंसित स्क्रीन स्थिति संरचना
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() और SharingStarted: तीन रणनीतियाँ

stateIn() एक ऑपरेटर है जो कोल्ड Flow को हॉट StateFlow में बदलता है। इसमें CoroutineScope (जहां आंतरिक कोरूटीन चलती है) और SharingStarted रणनीति निर्दिष्ट करने की आवश्यकता होती है। SharingStarted का सही चुनाव StateFlow के प्रदर्शन और जीवनचक्र को महत्वपूर्ण रूप से प्रभावित करता है।

kotlin
// 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% तक कम करता है।

कोड उदाहरण: Kotlin में StateFlow

उदाहरण 1: StateFlow और Compose के साथ ViewModel

एक पूर्ण खोज स्क्रीन जिसमें खोज क्वेरी, परिणाम और लोडिंग स्थिति है। ViewModel Compose के साथ रिएक्टिव संचार के लिए sealed class UIState और StateFlow का उपयोग करता है।

kotlin
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
}

उदाहरण 2: Room और combine के साथ StateFlow

Room (संस्करण 2.4.0 से) DAO से Flow लौटाने का समर्थन करता है। combine के माध्यम से कई Flows को संयोजित करना जटिल स्क्रीन के लिए एक शक्तिशाली पैटर्न है।

kotlin
@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 में कन्फ्लेशन (conflation) क्या है?

कन्फ्लेशन एक तंत्र है जिसमें StateFlow केवल अंतिम भेजे गए मान को रखता है। यदि सब्सक्राइबर द्वारा पिछले मान को संसाधित करने से पहले एक नया मान भेजा जाता है, तो मध्यवर्ती मान खो जाता है। यह UI के लिए महत्वपूर्ण है: यदि स्थिति Loading → Success → Error से बदलती है, और UI ने Success को रेंडर नहीं किया है, तो यह अतिरिक्त रेंडरिंग के बिना सीधे Error पर चला जाता है। कन्फ्लेशन एक प्रमुख Android ऑप्टिमाइज़ेशन है जो Compose में अत्यधिक रीकंपोज़िशन को रोकता है।

LiveData को StateFlow में कैसे बदलें?

lifecycle-livedata-ktx लाइब्रेरी से एक्सटेंशन फ़ंक्शन liveData.asFlow() का उपयोग करें, फिर StateFlow में बदलने के लिए .stateIn() का उपयोग करें। रिवर्स रूपांतरण stateFlow.asLiveData() है। रूपांतरण LiveData से StateFlow में माइग्रेट करते समय उपयोगी है: आप धीरे-धीरे ViewModels को StateFlow में बदल सकते हैं जबकि पुराने View को LiveData के माध्यम से सब्सक्राइब रख सकते हैं।

StateFlow को प्रारंभिक मान की आवश्यकता क्यों है?

StateFlow के पास हमेशा एक मान होना चाहिए — यह इंटरफ़ेस अनुबंध है: कोई भी नव-जुड़ा सब्सक्राइबर बिना प्रतीक्षा किए तुरंत वर्तमान स्थिति प्राप्त करता है। प्रारंभिक मान MutableStateFlow(initialValue) कंस्ट्रक्टर या stateIn(initialValue) ऑपरेटर को पास किया जाता है। यदि स्थिति अनुपस्थित हो सकती है, तो nullable प्रकार के साथ MutableStateFlow<T?>(null) का उपयोग करें और UI में null को हैंडल करें।

क्या StateFlow थ्रेड-सेफ है?

हाँ, StateFlow थ्रेड-सेफ है: value की रीडिंग और राइटिंग परमाणु संचालन (CAS) का उपयोग करती हैं। हालांकि, collect() एक suspend फ़ंक्शन है और इसे कोरूटीन में लॉन्च किया जाना चाहिए। यदि उत्सर्जन और संग्रह अलग-अलग थ्रेड्स पर होते हैं, तो StateFlow value पर सभी संचालनों के लिए happens-before की गारंटी देता है। View में StateFlow को इकट्ठा करने के लिए, lifecycleScope.launch { repeatOnLifecycle(STATE.STARTED) { stateFlow.collect { ... } } } का उपयोग करें।

एक ViewModel में कितने StateFlows रखे जा सकते हैं?

कोई कठोर सीमा नहीं है, लेकिन प्रति स्क्रीन 3-5 से अधिक अलग-अलग StateFlows का उपयोग न करने की अनुशंसा की जाती है। यदि अधिक विभिन्न स्थितियों की आवश्यकता है, तो उन्हें sealed class या data class के माध्यम से एक में संयोजित करें। प्रत्येक StateFlow को संग्रह के दौरान Continuation ऑब्जेक्ट के आवंटन की आवश्यकता होती है — सौ StateFlows GC पर ध्यान देने योग्य दबाव बना सकते हैं। Google की अनुशंसा के अनुसार, प्रति स्क्रीन एक sealed class UIState पढ़ने की क्षमता और प्रदर्शन के बीच इष्टतम संतुलन है।

सारांश

  • StateFlow — Kotlin Coroutines से एक हॉट रिएक्टिव कंटेनर (replay=1), हमेशा अंतिम मान रखता है।
  • StateFlow vs LiveData: StateFlow Lifecycle से स्वतंत्र है, कोरूटीन और मल्टीप्लेटफॉर्म का समर्थन करता है; LiveData में स्वचालित सब्सक्रिप्शन है।
  • MutableStateFlow private set और केवल-पढ़ने के लिए StateFlow प्रकाशित करना — ViewModel के लिए मानक पैटर्न।
  • UIState के रूप में Sealed class — जटिल स्क्रीन स्थितियों के प्रबंधन के लिए Google-अनुशंसित UDF दृष्टिकोण।
  • stateIn() WhileSubscribed(5000) के साथ — ViewModel के लिए कोल्ड Flow को StateFlow में बदलने की इष्टतम रणनीति।
  • Room DAO से Flow लौटाता है — StateFlow + combine + Room, Room + LiveData को बदलता है।
  • Google नए Kotlin प्रोजेक्ट्स के लिए StateFlow की अनुशंसा करता है, विशेष रूप से Jetpack Compose के साथ।

हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे

IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।

परियोजना पर चर्चा करें

यह भी पढ़ें