StateFlow : conteneur d’état actif pour l’interface utilisateur
Utilisez StateFlow comme conteneur d’état réactif et observez-le dans les ViewModels.
StateFlow : conteneur d’état actif pour l’interface utilisateur est une leçon Kotlin Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Kotlin Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Kotlin Academy comprend 4 leçons au total.
Qu'est-ce que StateFlow ?
StateFlow est un flux chaud qui conserve un état, possède toujours une valeur et émet les mises à jour vers tous les collecteurs. Il remplace LiveData dans les architectures Kotlin modernes.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val stateFlow = MutableStateFlow(0) // initial value
println("Current: ${stateFlow.value}")
stateFlow.value = 42
println("Updated: ${stateFlow.value}")
}MutableStateFlow et StateFlow
MutableStateFlow est l'implémentation mutable utilisée en interne. Exposez StateFlow (en lecture seule) aux observateurs externes en effectuant une conversion ou en utilisant .asStateFlow().
import kotlinx.coroutines.flow.*
class CounterViewModel {
private val _count = MutableStateFlow(0) // mutable internally
val count: StateFlow<Int> = _count.asStateFlow() // read-only externally
fun increment() { _count.value++ }
fun decrement() { _count.value-- }
}Collecte de StateFlow
Collectez StateFlow comme n'importe quel autre flux. La dernière valeur est émise immédiatement lors de la collecte.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val state = MutableStateFlow("loading")
launch {
state.collect { println("State: $it") }
}
delay(50); state.value = "success"
delay(50); state.value = "idle"
delay(50)
coroutineContext.cancelChildren()
}StateFlow regroupe les valeurs identiques
StateFlow n'émet que lorsque la valeur change. Si vous définissez deux fois la même valeur, une seule émission a lieu : les valeurs consécutives identiques sont regroupées.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = MutableStateFlow("A")
launch {
flow.collect { println("Received: $it") }
}
delay(50)
flow.value = "A" // no emission — same value
flow.value = "B" // emits
flow.value = "B" // no emission — same value
flow.value = "C" // emits
delay(50)
coroutineContext.cancelChildren()
}StateFlow dans ViewModel
Le modèle de référence avec ViewModel : un MutableStateFlow privé, modifié par la logique métier, et un StateFlow public, observé par l'interface utilisateur.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class UiState { object Loading : UiState(); data class Success(val data: String) : UiState(); data class Error(val msg: String) : UiState() }
class MyViewModel(scope: CoroutineScope) {
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
init {
scope.launch {
delay(100) // simulate load
_uiState.value = UiState.Success("Hello!")
}
}
}Mise à jour atomique
Utilisez update { } pour mettre à jour l'état de manière atomique à partir de sa valeur actuelle, ce qui est important en cas de mises à jour concurrentes.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val counter = MutableStateFlow(0)
List(100) {
launch(Dispatchers.Default) {
counter.update { it + 1 } // thread-safe atomic update
}
}.forEach { it.join() }
println("Counter: ${counter.value}") // 100
}compareAndSet pour les mises à jour optimistes
compareAndSet(expect, update) ne définit la nouvelle valeur que si la valeur actuelle correspond à expect. C'est utile pour la concurrence optimiste.
import kotlinx.coroutines.flow.*
fun main() {
val state = MutableStateFlow("idle")
val changed = state.compareAndSet("idle", "loading")
println("Changed: $changed, Value: ${state.value}") // true, loading
val changed2 = state.compareAndSet("idle", "error") // won't change
println("Changed: $changed2, Value: ${state.value}") // false, loading
}StateFlow et LiveData
StateFlow fonctionne sans cycle de vie Android. LiveData tient compte du cycle de vie, mais est limité à Android. Préférez StateFlow pour les ViewModels KMP partagés.
import kotlinx.coroutines.flow.*
// StateFlow: pure Kotlin, works in commonMain
// val state = MutableStateFlow("value")
// LiveData: Android-only, lifecycle-aware
// val liveData = MutableLiveData("value")
// In Compose, collect StateFlow with:
// val state by viewModel.uiState.collectAsState()
fun main() { println("StateFlow: multiplatform; LiveData: Android-only") }stateIn : convertir un flux froid en StateFlow
flow.stateIn(scope, started, initialValue) convertit un flux froid en StateFlow chaud, en partageant un seul abonnement entre tous les collecteurs.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val cold = flow {
println("Fetching...")
delay(100)
emit("data")
}
val hot: StateFlow<String> = cold.stateIn(
scope = this,
started = SharingStarted.Lazily,
initialValue = "loading"
)
launch { hot.collect { println("A: $it") } }
launch { hot.collect { println("B: $it") } }
delay(200)
coroutineContext.cancelChildren()
}Stratégies de partage
Avec empressement : démarre immédiatement. Avec paresse : démarre avec le premier collecteur. WhileSubscribed(stopTimeout) : s'arrête lorsqu'il n'y a plus de collecteurs et redémarre lorsqu'un collecteur s'abonne.
import kotlinx.coroutines.flow.*
// Eagerly: upstream starts right away
// SharingStarted.Eagerly
// Lazily: waits for first subscriber
// SharingStarted.Lazily
// WhileSubscribed: stops 5s after last subscriber
// SharingStarted.WhileSubscribed(5000)
// Typical ViewModel usage:
// val uiState = repo.dataFlow.stateIn(viewModelScope, WhileSubscribed(5000), Loading)Observer un état dérivé
Dérivez un nouveau StateFlow à partir d'un flux existant avec map + stateIn. Le flux dérivé est mis à jour chaque fois que la source change.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val count = MutableStateFlow(5)
val doubled = count.map { it * 2 }.stateIn(this, SharingStarted.Eagerly, 10)
println(doubled.value) // 10
count.value = 7
delay(50)
println(doubled.value) // 14
coroutineContext.cancelChildren()
}Vérification rapide
Que fait StateFlow lorsque vous définissez deux fois la même valeur ?
Récapitulatif
StateFlow est un flux chaud, toujours doté d'une valeur, qui regroupe les valeurs identiques. Utilisez MutableStateFlow en interne et exposez StateFlow en externe. Utilisez la mise à jour atomique pour les modifications concurrentes et stateIn() pour convertir les flux froids.
Questions Fréquemment Posées
La leçon « StateFlow : conteneur d’état actif pour l’interface utilisateur » est-elle gratuite ?
Oui — le texte complet de « StateFlow : conteneur d’état actif pour l’interface utilisateur » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Kotlin Academy, passe à CoddyKit PRO. Le cours Kotlin Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « StateFlow : conteneur d’état actif pour l’interface utilisateur » ?
Utilisez StateFlow comme conteneur d’état réactif et observez-le dans les ViewModels. Tu pratiques Kotlin Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Kotlin Academy ?
Aucune expérience préalable n'est requise. Kotlin Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « StateFlow : conteneur d’état actif pour l’interface utilisateur » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Kotlin Academy ?
Oui. Chaque leçon Kotlin Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- StateFlow : conteneur d’état actif pour l’interface utilisateur
- SharedFlow : bus d’événements et événements ponctuels
- Transformer un Flow froid en flux actif avec shareIn et stateIn
- Tester StateFlow et SharedFlow avec Turbine