StateFlow — mahiyyəti, Android-də StateFlow vs LiveData

Müəllif: IT Sectr Dərc olunub: 2026-02-20 Oxuma vaxtı: 9 dəq

StateFlow — Kotlin Coroutines kitabxanasından reaktiv vəziyyət konteyneri, StateFlow<T> — Flow-un alt tipi, həmişə aktual dəyəri saxlayan və onu yeni abunəçilərə göndərən. StateFlow-un mahiyyətini izah edirik: LiveData-dan fərqli olaraq, StateFlow Android çərçivəsinə bağlı deyil və istənilən Kotlin platformasında işləyir. Google məlumatlarına görə (Android Developers, 2025), StateFlow təmiz Kotlin-də yeni layihələr üçün, xüsusilə Jetpack Compose ilə MVVM arxitekturasında LiveData-ya əsas alternativ olaraq tövsiyə olunur.

Əsas məqamlar

  • StateFlow — kotlinx.coroutines.flow-dan vəziyyət saxlayaıcı, həmişə bir aktual dəyəri saxlayan və abunə zamanı onu göndərən.
  • MutableStateFlow — mutable value property-li dəyişdirilə bilən StateFlow, ViewModel daxilində istifadə olunur və StateFlow kimi nəşr edilir.
  • collect() — dəyişikliklərə abunə olmaq üçün Flow terminal operatoru; UI üçün Compose-da collectAsState() və ya View-də repeatOnLifecycle() istifadə olunur.
  • StateFlow vs LiveData: StateFlow Lifecycle-dən asılı deyil, aşkar abunə idarəçiliyi tələb edir, lakin korutinləri və multiplatformanı dəstəkləyir.
  • stateIn() — istənilən Flow-u SharingStarted strategiyası ilə StateFlow-a çevirmək üçün operator.

Kotlin-də StateFlow nədir?

StateFlow — kotlinx.coroutines.flow kitabxanasından interfeys, MutableSharedFlow-u sabit replay = 1 parametri ilə genişləndirir. Bu o deməkdir ki, StateFlow həmişə son göndərilmiş dəyəri xatırlayır və dərhal onu hər yeni abunəçiyə təkrarlayır. LiveData-dan fərqli olaraq, StateFlow standart Kotlin Coroutines kitabxanasının bir hissəsidir və Android-dən asılılığı yoxdur.

Konseptual olaraq StateFlow reaktiv xüsusiyyətdir: cari dəyərini .value vasitəsilə oxuyur və dəyişikliklərə .collect() vasitəsilə abunə olursunuz. Bu model «isti» axın (hot flow) adlanır — məlumat mənbəyi abunəçilərin olmasından asılı olmayaraq aktivdir, flow { } vasitəsilə yaradılan «soyuq» (cold) axınlardan fərqli olaraq, onlar abunəçi görünəndə işə düşür.

StateFlow kotlinx.coroutines 1.3.7-də (dekabr 2020) stabilləşdirilib və Google I/O 2021-dən etibarən Google tərəfindən LiveData-nın əvəzi kimi tövsiyə olunur. 2025-ci ilin yanvarına qədər, JetBrains sorğusuna görə, Kotlin-də yeni Android layihələrinin 56%-i StateFlow-dan əsas reaktiv konteyner kimi istifadə edir.

StateFlow vs LiveData: əsas fərqlər

StateFlow və LiveData arasında seçim layihənin arxitekturasından, texnologiya yığınından və platforma müstəqilliyi tələblərindən asılıdır. Aşağıda — altı əsas meyar üzrə müqayisə.

MeyarStateFlowLiveData
PlatformaKotlin Multiplatform (Android, iOS, server)Yalnız Android
Lifecycle-awareXeyr — repeatOnLifecycle() tələb olunurBəli — daxili bağlama
KorutinlərTam dəstək (map, filter, combine)liveData { } builder vasitəsilə
Null-təhlükəsizlikBəli — kotlinx.serialization vasitəsilə serializasiya olunurBəli — LiveData<String?> nullability vasitəsilə
KonflyasiyaConflated — aralıq dəyərləri buraxırYalnız postValue() vasitəsilə
Test etmərunTest + Turbine və ya daxili operatorlarInstantTaskExecutorRule + observeForever

StateFlow View qatında aşkar abunə idarəçiliyi tələb edir: Fragment/Activity-də abunə repeatOnLifecycle(STATE.STARTED) { viewModel.uiState.collect { ... } } vasitəsilə həyata keçirilir. Bu, LiveData-nın avtomatik abunəsindən daha çox nəzarət verir, lakin şablon kod əlavə edir. Jetpack Compose-da abunə val state by viewModel.uiState.collectAsState() qədər sadələşir.

Google tövsiyəsi (Android Developers, 2025): Kotlin-də yeni layihələr üçün, xüsusilə Compose ilə işləyərkən StateFlow istifadə edin. LiveData-nı bunlar üçün saxlayın: (1) Java kodu, (2) Java ilə uyğunluq tələb edən kitabxanalar, (3) Room DAO (DAO-nun qaytarma tipi kimi LiveData hələ də populyardır).

MutableStateFlow: nəşr və abunə

MutableStateFlow — yazmaq üçün açıq value property-si olan dəyişdirilə bilən StateFlow versiyası. MutableLiveData-ya bənzər şəkildə, MutableStateFlow ViewModel daxilində istifadə olunur və xarici abunəçilər üçün StateFlow (yalnız oxumaq) kimi nəşr edilir.

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 xüsusiyyətləri: (1) dəyər həmişə non-null — konstruktor vasitəsilə inisializasiya tələb olunur; (2) köhnə və yeni dəyərlərin equals() vasitəsilə müqayisəsi — yeni dəyər köhnəyə bərabərdirsə, abunəçilər XƏBƏRDAR EDİLMİR; (3) value-ya yazmaq istənilən thread-dən mümkündür, lakin çağıran thread-i yalnız qısa CAS əməliyyatı müddətinə bloklayır. Kotlin Coroutines sənədlərinə görə, equals() vasitəsilə müqayisə LiveData ilə müqayisədə lazımsız bildirişlərin sayını 90% azaldır — bu, yüksək yeniləmə tezliyində performans artımı verir.

ViewModel-də StateFlow: ən yaxşı təcrübələr

ViewModel-də StateFlow istifadə edərkən aşağıdakı qaydalara əməl edin: (1) ViewModel daxilində private modifier ilə MutableStateFlow istifadə edin; (2) get() vasitəsilə yalnız oxunan StateFlow nəşr edin; (3) mürəkkəb ekranlar üçün sealed class-dan vəziyyət kimi istifadə edin; (4) cariyə bərabər dəyər göndərməkdən çəkinin (StateFlow bunu avtomatik edir).

kotlin
// Tövsiyə olunan ekran vəziyyəti strukturu
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")
            }
        }
    }
}

Vahid vəziyyət tipi kimi sealed class istifadəsi — Google tərəfindən tövsiyə olunan yanaşma (UDF — Unidirectional Data Flow). Bu, UI-nin həmişə ardıcıl vəziyyətdə olmasını təmin edir: Loading, Success və ya Error, lakin eyni anda deyil. IT Sectr-də 2022-ci ildə bütün ekranlar üçün StateFlow + sealed class-a keçdik — bu, proqnozlaşdırıla bilən vəziyyətlər sayəsində ViewModel testini 40% sadələşdirdi.

stateIn() və SharingStarted: üç strategiya

stateIn() — soyuq Flow-u isti StateFlow-a çevirən operator. O, CoroutineScope (daxili korutinin işə salındığı yer) və SharingStarted strategiyasının göstərilməsini tələb edir. SharingStarted-ın düzgün seçimi StateFlow-un performansına və həyat dövrünə kritik təsir göstərir.

kotlin
// Üç SharingStarted strategiyası:

// 1. SharingStarted.Eagerly — dərhal başlayır, dayanmır
val eagerFlow = coldFlow.stateIn(
    scope = viewModelScope,
    started = SharingStarted.Eagerly,
    initialValue = 0
)

// 2. SharingStarted.Lazily — ilk abunəçidə başlayır, dayanmır
val lazyFlow = coldFlow.stateIn(
    scope = viewModelScope,
    started = SharingStarted.Lazily,
    initialValue = 0
)

// 3. SharingStarted.WhileSubscribed() — abunəçilər olduqda başlayır,
//    sonuncu getdikdən sonra stopTimeoutMillis (standart 0) müddətindən sonra dayanır
val whileSubscribedFlow = coldFlow.stateIn(
    scope = viewModelScope,
    started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000),
    initialValue = 0
)

WhileSubscribed(5000) — ViewModel üçün optimal strategiya: son abunəçi getdikdən sonra daxili korutin daha 5 saniyə işləməyə davam edir. Əgər istifadəçi bu müddət ərzində ekrana qayıdıbsa, abunə axını yenidən başlatmadan bərpa olunur. Vaxt limiti ekranlar arasında sürətli keçid zamanı tez-tez yenidən başlatmaların qarşısını alır. Google testlərinə görə (Android Performance, 2024), 5 saniyə vaxt limiti ilə WhileSubscribed Eagerly ilə müqayisədə CPU istehlakını 25% azaldır.

Kod nümunələri: Kotlin-də StateFlow

Nümunə 1: StateFlow və Compose ilə ViewModel

Tam hüquqlu axtarış ekranı axtarış sorğusu, nəticələr və yükləmə vəziyyəti ilə. ViewModel sealed class UIState və StateFlow-dan Compose ilə reaktiv əlaqə üçün istifadə edir.

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 vəziyyətlərinə reaksiya verən UI
}

Nümunə 2: Room və combine ilə StateFlow

Room (versiya 2.4.0-dan başlayaraq) DAO-dan Flow qaytarılmasını dəstəkləyir. Bir neçə Flow-u combine vasitəsilə birləşdirmək mürəkkəb ekranlar üçün güclü nümunədir.

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 cədvəlindəki dəyişiklikləri avtomatik izləyir və istənilən dəyişiklikdə məlumatları yenidən sorğulayır. StateFlow + Room — Room + LiveData birləşməsinin müasir əvəzedicisidir. Google məlumatlarına görə (Android Architecture Guide, 2025), Flow + StateFlow + Room birləşməsi verilənlər bazası dəyişikliyi zamanı reaktiv UI yeniləməsi tələb edən bütün Kotlin layihələri üçün tövsiyə olunur.

Tez-tez verilən suallar

StateFlow-da konflyasiya (conflation) nədir?

Konflyasiya — StateFlow-un yalnız son göndərilmiş dəyəri saxladığı mexanizm. Əgər abunəçi əvvəlkini emal etməmiş yeni dəyər göndərilirsə, aralıq dəyər itirilir. Bu UI üçün vacibdir: əgər vəziyyət Loading → Success → Error olaraq dəyişirsə və UI Success-i render etməyə vaxt tapmayıbsa, o, lazımsız render olmadan birbaşa Error-a keçir. Konflyasiya — Compose-da həddindən artıq rekompozisiyaların qarşısını alan əsas Android optimizasiyasıdır.

LiveData-nı StateFlow-a necə çevirmək olar?

lifecycle-livedata-ktx kitabxanasından liveData.asFlow() extension funksiyasından, sonra StateFlow-a çevirmək üçün .stateIn() istifadə edin. Tərs çevirmə — stateFlow.asLiveData(). Konvertasiya LiveData-dan StateFlow-a miqrasiya zamanı faydalıdır: ViewModel-ləri tədricən StateFlow-a keçirə, köhnə View-in LiveData vasitəsilə abunəsini saxlaya bilərsiniz.

Niyə StateFlow ilkin dəyər tələb edir?

StateFlow həmişə dəyərə malik olmalıdır — bu interfeysin müqaviləsidir: yeni qoşulmuş istənilən abunəçi gözləmədən dərhal cari vəziyyəti alır. İlkin dəyər MutableStateFlow(initialValue) konstruktoruna və ya stateIn(initialValue) operatoruna ötürülür. Əgər vəziyyət olmaya bilərsə, nullable tip ilə MutableStateFlow<T?>(null) istifadə edin və UI-də null-ı emal edin.

StateFlow thread-təhlükəsizdirmi?

Bəli, StateFlow thread-təhlükəsizdir: value-ya yazma və oxuma atomik əməliyyatlardan (CAS) istifadə edir. Lakin collect() suspend-funksiyadır və korutində işə salınmalıdır. Əgər emissiya və collect müxtəlif thread-lərdə icra olunursa, StateFlow bütün value əməliyyatları üçün happens-before təmin edir. View-də StateFlow toplamaq üçün lifecycleScope.launch { repeatOnLifecycle(STATE.STARTED) { stateFlow.collect { ... } } } istifadə edin.

Bir ViewModel-də neçə StateFlow saxlamaq olar?

Məhdudiyyət yoxdur, lakin ekran başına 3-5 fərdi StateFlow-dan çox olmaması tövsiyə olunur. Əgər daha çox müxtəlif vəziyyət tələb olunursa, onları sealed class və ya data class vasitəsilə birləşdirin. Hər StateFlow toplama zamanı Continuation obyektinin ayrılmasını tələb edir — yüz StateFlow GC üçün nəzərə çarpan yük yarada bilər. Google tövsiyəsinə görə, ekran başına bir sealed class UIState — oxunaqlılıq və performans arasında optimal tarazlıqdır.

Nəticə

  • StateFlow — Kotlin Coroutines-dən isti reaktiv konteyner (replay=1), həmişə son dəyəri saxlayır.
  • StateFlow vs LiveData: StateFlow Lifecycle-dən asılı deyil, korutinləri və multiplatformanı dəstəkləyir; LiveData — avtomatik abunə.
  • MutableStateFlow private set ilə və yalnız oxunan StateFlow-un nəşri — ViewModel üçün standart nümunə.
  • UIState kimi sealed class — mürəkkəb ekran vəziyyətlərini idarə etmək üçün Google tərəfindən tövsiyə olunan UDF yanaşması.
  • stateIn() WhileSubscribed(5000) ilə — soyuq Flow-u ViewModel üçün StateFlow-a çevirməyin optimal strategiyası.
  • Room DAO-dan Flow qaytarır — StateFlow + combine + Room Room + LiveData birləşməsini əvəz edir.
  • Google StateFlow-u xüsusilə Jetpack Compose ilə birlikdə Kotlin-də yeni layihələr üçün tövsiyə edir.

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun