Saltar al contenido principal
A
ArceApps

StateFlow vs SharedFlow: Guía Definitiva para Android

calendar_today
StateFlow vs SharedFlow: Guía Definitiva para Android

🌊 Teoría: Hot Flows

Tanto StateFlow como SharedFlow son Hot Flows.

  • Cold Flow (Flow normal): El código dentro del flow { ... } no se ejecuta hasta que alguien llama a collect(). Cada colector reinicia el flujo.
  • Hot Flow: El flujo está activo independientemente de si hay colectores. Los datos se emiten y si nadie escucha, se pierden (o se guardan en buffer).

📦 StateFlow: El Sucesor de LiveData

StateFlow es una especialización de SharedFlow diseñada para mantener estado.

Características Clave

  1. Siempre tiene valor: Requiere un valor inicial. state.value siempre es seguro.
  2. Conflated: Solo emite el último valor. Si emites “A”, “B”, “C” muy rápido y el colector es lento, solo recibirá “C”. “A” y “B” se pierden (conflation).
  3. DistinctUntilChanged: Si emites “A” y luego “A” otra vez, no notifica a los colectores.

Uso Perfecto: Estado de UI (UiState).

private val _uiState = MutableStateFlow(UiState.Loading)
val uiState = _uiState.asStateFlow()

📢 SharedFlow: El Bus de Eventos

SharedFlow es más configurable y general. No necesita valor inicial y puede reemitir valores antiguos (replay) o no.

Configuración

val sharedFlow = MutableSharedFlow<Event>(
    replay = 0,      // Cuántos valores viejos enviar a nuevos suscriptores
    extraBufferCapacity = 0,
    onBufferOverflow = BufferOverflow.SUSPEND
)

Uso Perfecto: Eventos de una sola vez (“One-off events”) como Toasts, Navegación, Snackbars. Para eventos, usa replay = 0.

⚠️ La Trampa del Lifecycle

LiveData pausaba la observación automáticamente cuando la Activity estaba en STOPPED. Los Flows NO.

Si colectas un Flow en lifecycleScope.launch directamente, seguirá colectando en background, gastando recursos y pudiendo crashear si intenta actualizar la UI.

La Solución Correcta

// En Activity/Fragment
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { ... }
    }
}

O usando la extensión de lifecycle-runtime-compose en Jetpack Compose:

val state by viewModel.uiState.collectAsStateWithLifecycle()

🎯 Tabla Comparativa

CaracterísticaStateFlowSharedFlowLiveData
Valor InicialObligatorioOpcionalOpcional
Replay1 (Fijo)Configurable1 (Último valor)
ConflationConfigurable
DistinctNoNo
Lifecycle AwareNo (requiere wrapper)No
ThreadingFlowOn / ContextFlowOn / ContextMain Thread Forzado

🎯 Conclusión

La migración es clara:

  • LiveData -> StateFlow (Para Estado)
  • SingleLiveEvent -> SharedFlow (Para Eventos)

Dominar estos dos tipos de Flows te da control total sobre la reactividad de tu aplicación, permitiendo patrones potentes y seguros.

Artículos relacionados

Kotlin Coroutines en Android: Programación Asíncrona Moderna
Android 20 de septiembre de 2025

Kotlin Coroutines en Android: Programación Asíncrona Moderna

Domina las corrutinas de Kotlin para crear aplicaciones Android más eficientes y reactivas, siguiendo las mejores prácticas de arquitectura limpia y MVVM.

Leer artículo arrow_forward
Clean Architecture: La Guía Definitiva para Android Moderno
Architecture 15 de octubre de 2025

Clean Architecture: La Guía Definitiva para Android Moderno

Desmitificando Clean Architecture: Una inmersión profunda en capas, dependencias y flujo de datos para construir apps Android indestructibles.

Leer artículo arrow_forward
MVVM ViewModel: El Cerebro de la Operación
Android 4 de octubre de 2025

MVVM ViewModel: El Cerebro de la Operación

Profundiza en el componente ViewModel: Gestión de estado, ciclo de vida, corrutinas y cómo evitar los errores más comunes de diseño.

Leer artículo arrow_forward