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
collectAsState() yoki View-da repeatOnLifecycle() ishlatiladi.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 va LiveData o'rtasidagi tanlov loyiha arxitekturasi, texnologiya to'plami va platforma mustaqilligi talablariga bog'liq. Quyida — oltita asosiy mezon bo'yicha taqqoslash.
| Mezon | StateFlow | LiveData |
|---|---|---|
| Platforma | Kotlin Multiplatform (Android, iOS, server) | Faqat Android |
| Lifecycle-aware | Yo'q — repeatOnLifecycle() talab qilinadi | Ha — o'rnatilgan bog'lash |
| Korutinlar | To'liq qo'llab-quvvatlash (map, filter, combine) | liveData { } builder orqali |
| Null-xavfsizlik | Ha — kotlinx.serialization orqali seriyalanadi | Ha — LiveData<String?> nullability orqali |
| Konflyatsiya | Conflated — oraliq qiymatlarni o'tkazib yuboradi | Faqat postValue() orqali |
| Test qilish | runTest + Turbine yoki o'rnatilgan operatorlar | InstantTaskExecutorRule + 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 — 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.
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 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).
// 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() — 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.
// 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.
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.
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
}
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.
@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
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.
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.
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.
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.
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
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.