MVVM ViewModel: El Cerebro de la Operación
Índice de contenidos
🧠 Teoría: ¿Qué hace a un ViewModel un ViewModel?
El ViewModel de Android es una clase diseñada con un superpoder específico: sobrevivir a cambios de configuración.
Cuando rotas el teléfono:
Activitymuere (onDestroy).Activityrenace (onCreate).ViewModelse queda quieto.
Esto lo convierte en el lugar perfecto para mantener el estado (datos) y las operaciones asíncronas en curso. Si no usáramos ViewModel, al rotar la pantalla mientras cargamos datos de red, la petición se cancelaría o perderíamos el resultado.
🏗️ Estructura Canónica de un ViewModel Moderno
Hoy en día, un ViewModel profesional sigue un patrón estricto basado en StateFlow.
@HiltViewModel
class ProductViewModel @Inject constructor(
private val getProductsUseCase: GetProductsUseCase // Inyección de dependencias
) : ViewModel() {
// 1. Backing Property: Estado mutable privado
private val _uiState = MutableStateFlow<ProductUiState>(ProductUiState.Loading)
// 2. Estado inmutable público (Read-only)
val uiState: StateFlow<ProductUiState> = _uiState.asStateFlow()
init {
// 3. Carga inicial automática
loadProducts()
}
// 4. Funciones públicas (User Intents)
fun refresh() {
loadProducts()
}
private fun loadProducts() {
// 5. viewModelScope: Corrutinas atadas a la vida del VM
viewModelScope.launch {
_uiState.value = ProductUiState.Loading
getProductsUseCase()
.catch { e ->
_uiState.value = ProductUiState.Error(e.message)
}
.collect { products ->
_uiState.value = ProductUiState.Success(products)
}
}
}
}
🚦 Modelando el Estado (State Modeling)
¿Cómo representamos la UI? Tenemos dos escuelas de pensamiento.
1. Sealed Interface (Recomendado para pantallas completas)
Representa estados mutuamente excluyentes. No puedes estar cargando y tener éxito a la vez.
sealed interface ProductUiState {
object Loading : ProductUiState
data class Success(val products: List<Product>) : ProductUiState
data class Error(val msg: String?) : ProductUiState
}
2. Data Class con Flags (Recomendado para formularios complejos)
Útil cuando los campos son independientes.
data class FormUiState(
val email: String = "",
val isEmailValid: Boolean = false,
val isLoading: Boolean = false,
val errors: List<String> = emptyList()
)
⚠️ El Problema de los “One-Off Events” (Eventos Únicos)
¿Cómo manejamos un Toast o una Navegación? No son estado, son eventos efímeros. Si usas un StateFlow para mostrar un Toast de error, al rotar la pantalla, el Toast volverá a salir (porque el estado sigue siendo “Error”).
La Solución Moderna: Canales (Channels)
Usa un Channel para eventos de “disparar y olvidar”.
private val _events = Channel<ProductEvent>()
val events = _events.receiveAsFlow()
fun deleteProduct() {
viewModelScope.launch {
try {
repo.delete()
_events.send(ProductEvent.ShowUndoSnackBar) // Se consume una vez
} catch (e: Exception) {
_events.send(ProductEvent.ShowToast("Error"))
}
}
}
🚫 Anti-Patrones en ViewModels
-
Context en ViewModel: ❌
class MyVM(context: Context)Nunca. Si rotas la pantalla, elActivitycontext se destruye, pero el VM sigue vivo -> Memory Leak. Si necesitas recursos, usaAndroidViewModel(application)o mejor, inyecta un wrapper. -
Exponer MutableState: ❌
val state = MutableStateFlow(...)La View podría modificar el estado accidentalmente (viewModel.state.value = ...). Rompe el flujo unidireccional. Siempre expónStateFlowoLiveDatainmutable. -
Lógica de Negocio Masiva: El VM es un orquestador. Si tienes
ifanidados de 50 líneas validando reglas de negocio, muévelo a un Use Case. El VM debe ser ligero.
🎯 Conclusión
El ViewModel es el cerebro de la UI, pero debe ser un cerebro enfocado. Su trabajo es transformar datos crudos en estado listo para la UI y manejar la concurrencia. Si mantienes tus ViewModels limpios, agnósticos del framework Android y bien testados, tendrás la mitad de la batalla de la arquitectura ganada.
Artículos relacionados
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.
MVVM View: UI Inteligente pero Pasiva en Android
Aprende a implementar la capa View en MVVM correctamente, ya sea con XML o Jetpack Compose. Evita lógica en la UI y domina el Unidirectional Data Flow.
MVVM Model: La Capa de Datos Invisible pero Vital
El 'Model' en MVVM es mucho más que clases de datos. Aprende a diseñar una capa de modelo robusta que sobreviva a cambios de UI y backend.