StateFlow — mohiyati, Android-da StateFlow vs LiveData

Muallif: IT Sectr Nashr etilgan: 2026-02-20 O'qish vaqti: 9 daq

StateFlow — Kotlin Coroutines kutubxonasidan reaktiv holat konteyneri, StateFlow<T> — Flow-ning kichik turi, har doim dolzarb qiymatni saqlaydi va uni yangi obunachilarga yuboradi. StateFlow mohiyatini tushuntiramiz: LiveData-dan farqli o'laroq, StateFlow Android freymvorkiga bog'liq emas va istalgan Kotlin platformasida ishlaydi. Google ma'lumotlariga ko'ra (Android Developers, 2025), StateFlow toza Kotlin-dagi yangi loyihalar uchun, ayniqsa Jetpack Compose bilan MVVM arxitekturasida LiveData-ga asosiy muqobil sifatida tavsiya etiladi.

Asosiy ma'lumotlar

  • StateFlow — kotlinx.coroutines.flow dan holat saqlagich, har doim bitta dolzarb qiymatni saqlaydi va obuna bo'lganda uni yuboradi.
  • MutableStateFlow — mutable value property bilan o'zgartiriladigan StateFlow, ViewModel ichida ishlatiladi va StateFlow sifatida nashr qilinadi.
  • collect() — o'zgarishlarga obuna bo'lish uchun Flow terminal operatori; UI uchun Compose-da collectAsState() yoki View-da repeatOnLifecycle() ishlatiladi.
  • StateFlow vs LiveData: StateFlow Lifecycle-ga bog'liq emas, aniq obuna boshqaruvini talab qiladi, lekin korutinlar va multiplatformani qo'llab-quvvatlaydi.
  • stateIn() — istalgan Flow-ni SharingStarted strategiyasi bilan StateFlow-ga aylantirish operatori.

Kotlin-da StateFlow nima?

StateFlow — kotlinx.coroutines.flow kutubxonasidan interfeys, u MutableSharedFlow-ni qat'iy replay = 1 parametri bilan kengaytiradi. Bu StateFlow har doim oxirgi yuborilgan qiymatni eslab qoladi va darhol har bir yangi obunachiga uni takrorlaydi degani. LiveData-dan farqli o'laroq, StateFlow standart Kotlin Coroutines kutubxonasining bir qismi va Android-ga bog'liqlikka ega emas.

Kontseptual jihatdan StateFlow reaktiv xususiyatdir: siz uning joriy qiymatini .value orqali o'qiysiz va o'zgarishlarga .collect() orqali obuna bo'lasiz. Bu model «issiq» oqim (hot flow) deb ataladi — ma'lumot manbai obunachilar mavjudligidan qat'iy nazar faol, flow { } orqali yaratiladigan «sovuq» (cold) oqimlardan farqli o'laroq, ular obunachi paydo bo'lganda ishga tushadi.

StateFlow kotlinx.coroutines 1.3.7 (dekabr 2020) da barqarorlashtirildi va Google I/O 2021 dan boshlab Google tomonidan LiveData-ning o'rnini bosuvchi sifatida tavsiya etildi. 2025 yil yanvarigacha, JetBrains so'roviga ko'ra, Kotlin-dagi yangi Android loyihalarining 56% i StateFlow-dan asosiy reaktiv konteyner sifatida foydalanadi.

StateFlow vs LiveData: asosiy farqlar

StateFlow va LiveData o'rtasidagi tanlov loyiha arxitekturasi, texnologiya to'plami va platforma mustaqilligi talablariga bog'liq. Quyida — oltita asosiy mezon bo'yicha taqqoslash.

MezonStateFlowLiveData
PlatformaKotlin Multiplatform (Android, iOS, server)Faqat Android
Lifecycle-awareYo'q — repeatOnLifecycle() talab qilinadiHa — o'rnatilgan bog'lash
KorutinlarTo'liq qo'llab-quvvatlash (map, filter, combine)liveData { } builder orqali
Null-xavfsizlikHa — kotlinx.serialization orqali seriyalanadiHa — LiveData<String?> nullability orqali
KonflyatsiyaConflated — oraliq qiymatlarni o'tkazib yuboradiFaqat postValue() orqali
Test qilishrunTest + Turbine yoki o'rnatilgan operatorlarInstantTaskExecutorRule + observeForever

StateFlow View qatlamida aniq obuna boshqaruvini talab qiladi: Fragment/Activity da obuna repeatOnLifecycle(STATE.STARTED) { viewModel.uiState.collect { ... } } orqali amalga oshiriladi. Bu LiveData-ning avtomatik obunasidan ko'proq nazorat beradi, lekin shablon kod qo'shadi. Jetpack Compose-da obuna val state by viewModel.uiState.collectAsState() ga soddalashadi.

Google tavsiyasi (Android Developers, 2025): Kotlin-dagi yangi loyihalar uchun, ayniqsa Compose bilan ishlaganda StateFlow dan foydalaning. LiveData-ni buning uchun qoldiring: (1) Java kodi, (2) Java bilan moslik talab qiladigan kutubxonalar, (3) Room DAO (DAO qaytarish turi sifatida LiveData hali ham mashhur).

MutableStateFlow: nashr va obuna

MutableStateFlow — yozish uchun ochiq value xususiyatiga ega o'zgartiriladigan StateFlow versiyasi. MutableLiveData-ga o'xshab, MutableStateFlow ViewModel ichida ishlatiladi va tashqi obunachilar uchun StateFlow (faqat o'qish) sifatida nashr qilinadi.

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 xususiyatlari: (1) qiymat har doim non-null — konstruktor orqali boshlang'ich qiymat berish talab qilinadi; (2) eski va yangi qiymatlarni equals() orqali solishtirish — agar yangi qiymat eskisiga teng bo'lsa, obunachilar XABARDOR QILINMAYDI; (3) value-ga yozish istalgan thread-dan mumkin, lekin chaqiruvchi thread-ni faqat qisqa CAS operatsiyasi vaqtiga bloklaydi. Kotlin Coroutines hujjatlariga ko'ra, equals() orqali solishtirish LiveData bilan solishtirganda keraksiz bildirishnomalar sonini 90% kamaytiradi — bu yuqori yangilanish chastotasida ishlash samaradorligini oshiradi.

ViewModel-da StateFlow: eng yaxshi amaliyotlar

ViewModel-da StateFlow dan foydalanganda quyidagi qoidalarga rioya qiling: (1) ViewModel ichida private modifier bilan MutableStateFlow dan foydalaning; (2) get() orqali faqat o'qiladigan StateFlow-ni nashr qiling; (3) murakkab ekranlar uchun sealed class dan holat sifatida foydalaning; (4) joriyga teng qiymatni yuborishdan saqlaning (StateFlow buni avtomatik qiladi).

kotlin
// Tavsiya etiladigan ekran holati tuzilmasi
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")
            }
        }
    }
}

Yagona holat turi sifatida sealed class dan foydalanish — Google tomonidan tavsiya etilgan yondashuv (UDF — Unidirectional Data Flow). Bu UI har doim izchil holatda bo'lishini kafolatlaydi: Loading, Success yoki Error, lekin bir vaqtning o'zida emas. IT Sectr da 2022 yilda barcha ekranlar uchun StateFlow + sealed class ga o'tdik — bu bashorat qilinadigan holatlar tufayli ViewModel testini 40% soddalashtirdi.

stateIn() va SharingStarted: uch strategiya

stateIn() — sovuq Flow-ni issiq StateFlow-ga aylantiruvchi operator. U CoroutineScope (ichki korutin ishga tushiriladigan joy) va SharingStarted strategiyasini ko'rsatishni talab qiladi. SharingStarted ni to'g'ri tanlash StateFlow ning ishlashi va hayotiy sikliga kritik ta'sir ko'rsatadi.

kotlin
// Uchta SharingStarted strategiyasi:

// 1. SharingStarted.Eagerly — darhol boshlanadi, to'xtamaydi
val eagerFlow = coldFlow.stateIn(
    scope = viewModelScope,
    started = SharingStarted.Eagerly,
    initialValue = 0
)

// 2. SharingStarted.Lazily — birinchi obunachida boshlanadi, to'xtamaydi
val lazyFlow = coldFlow.stateIn(
    scope = viewModelScope,
    started = SharingStarted.Lazily,
    initialValue = 0
)

// 3. SharingStarted.WhileSubscribed() — obunachilar borida boshlanadi,
//    oxirgisi ketgandan so'ng stopTimeoutMillis (standart 0) dan keyin to'xtaydi
val whileSubscribedFlow = coldFlow.stateIn(
    scope = viewModelScope,
    started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000),
    initialValue = 0
)

WhileSubscribed(5000) — ViewModel uchun optimal strategiya: oxirgi obunachi ketgandan so'ng ichki korutin yana 5 soniya ishlashda davom etadi. Agar foydalanuvchi shu vaqt ichida ekranga qaytsa, obuna oqimni qayta ishga tushirmasdan tiklanadi. Vaqt chegarasi ekranlar orasida tez almashishda tez-tez qayta ishga tushirishlarning oldini oladi. Google testlariga ko'ra (Android Performance, 2024), 5 soniya vaqt chegarasi bilan WhileSubscribed Eagerly bilan solishtirganda CPU sarfini 25% kamaytiradi.

Kod misollari: Kotlin-da StateFlow

1-misol: StateFlow va Compose bilan ViewModel

To'liq qidiruv ekrani qidiruv so'rovi, natijalar va yuklash holati bilan. ViewModel sealed class UIState va StateFlow dan Compose bilan reaktiv aloqa uchun foydalanadi.

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 da:
@Composable
fun SearchScreen(viewModel: SearchViewModel = hiltViewModel()) {
    val uiState by viewModel.uiState.collectAsState()
    // ... Loading, Results, Error holatlariga reaksiya beruvchi UI
}

2-misol: Room va combine bilan StateFlow

Room (2.4.0 versiyasidan boshlab) DAO dan Flow qaytarishni qo'llab-quvvatlaydi. Bir nechta Flow-larni combine orqali birlashtirish murakkab ekranlar uchun kuchli namunadir.

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 jadvalidagi o'zgarishlarni avtomatik kuzatadi va har qanday o'zgarishda ma'lumotlarni qayta so'raydi. StateFlow + Room — Room + LiveData birikmasining zamonaviy o'rnini bosuvchisi. Google ma'lumotlariga ko'ra (Android Architecture Guide, 2025), Flow + StateFlow + Room birikmasi ma'lumotlar bazasi o'zgarishida reaktiv UI yangilanishini talab qiladigan barcha Kotlin loyihalari uchun tavsiya etiladi.

Tez-tez beriladigan savollar

StateFlow da konflyatsiya (conflation) nima?

Konflyatsiya — StateFlow faqat oxirgi yuborilgan qiymatni saqlaydigan mexanizm. Agar obunachi avvalgisini qayta ishlamasdan yangi qiymat yuborilsa, oraliq qiymat yo'qoladi. Bu UI uchun muhim: agar holat Loading → Success → Error ga o'zgar sa va UI Success ni render qilishga ulgurmasa, u keraksiz renderlarsiz to'g'ridan-to'g'ri Error ga o'tadi. Konflyatsiya — Compose-da ortiqcha rekompozitsiyalarning oldini oluvchi asosiy Android optimizatsiyasidir.

LiveData ni StateFlow ga qanday aylantirish mumkin?

lifecycle-livedata-ktx kutubxonasidan liveData.asFlow() extension funksiyasidan, so'ng StateFlow ga aylantirish uchun .stateIn() dan foydalaning. Teskari konvertatsiya — stateFlow.asLiveData(). Konvertatsiya LiveData dan StateFlow ga migratsiya paytida foydalidir: siz ViewModel-larni asta-sekin StateFlow ga o'tkazib, eski View ning LiveData orqali obunasini saqlab qolishingiz mumkin.

Nega StateFlow boshlang'ich qiymat talab qiladi?

StateFlow har doim qiymatga ega bo'lishi kerak — bu interfeys shartnomasi: har qanday yangi ulangan obunachi kutmasdan darhol joriy holatni oladi. Boshlang'ich qiymat MutableStateFlow(initialValue) konstruktoriga yoki stateIn(initialValue) operatoriga uzatiladi. Agar holat bo'lmasligi mumkin bo'lsa, nullable tur bilan MutableStateFlow<T?>(null) dan foydalaning va UI da null ni qayta ishlang.

StateFlow thread-xavfsizmi?

Ha, StateFlow thread-xavfsiz: value ga yozish va o'qish atomik operatsiyalardan (CAS) foydalanadi. Biroq collect() suspend-funksiya va korutinda ishga tushirilishi kerak. Agar emissiya va collect turli thread-larda bajarilsa, StateFlow value bo'yicha barcha operatsiyalar uchun happens-before ni kafolatlaydi. View-da StateFlow ni yig'ish uchun lifecycleScope.launch { repeatOnLifecycle(STATE.STARTED) { stateFlow.collect { ... } } } dan foydalaning.

Bitta ViewModel da nechta StateFlow saqlash mumkin?

Cheklov yo'q, lekin ekran uchun 3-5 ta alohida StateFlow dan ko'p bo'lmasligi tavsiya etiladi. Agar ko'proq turli holatlar kerak bo'lsa, ularni sealed class yoki data class orqali birlashtiring. Har bir StateFlow yig'ish paytida Continuation obyektini ajratishni talab qiladi — yuzta StateFlow GC uchun sezilarli yuk yaratishi mumkin. Google tavsiyasiga ko'ra, ekran uchun bitta sealed class UIState — o'qilishi va ishlash o'rtasidagi optimal muvozanatdir.

Xulosa

  • StateFlow — Kotlin Coroutines dan issiq reaktiv konteyner (replay=1), har doim oxirgi qiymatni saqlaydi.
  • StateFlow vs LiveData: StateFlow Lifecycle-ga bog'liq emas, korutinlar va multiplatformani qo'llab-quvvatlaydi; LiveData — avtomatik obuna.
  • MutableStateFlow private set bilan va faqat o'qiladigan StateFlow nashri — ViewModel uchun standart namuna.
  • UIState sifatida sealed class — murakkab ekran holatlarini boshqarish uchun Google tomonidan tavsiya etilgan UDF yondashuvi.
  • stateIn() WhileSubscribed(5000) bilan — sovuq Flow ni ViewModel uchun StateFlow ga aylantirishning optimal strategiyasi.
  • Room DAO dan Flow qaytaradi — StateFlow + combine + Room Room + LiveData birikmasini almashtiradi.
  • Google StateFlow ni ayniqsa Jetpack Compose bilan birgalikda Kotlin-dagi yangi loyihalar uchun tavsiya qiladi.

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing