El ViewModel es un componente esencial en la arquitectura de Android, particularmente en Jetpack Compose, ya que permite separar la lógica de negocio y los datos del ciclo de vida de la interfaz gráfica.
Los ViewModel están diseñados para:
Almacenar y gestionar datos de estado relacionados con la UI.
Sobrevivir a cambios de configuración como rotación de pantalla.
Facilitar la conexión entre la UI y la lógica de negocio.
En Jetpack Compose, un ViewModel permite emitir estados observables hacia las composables de forma reactiva.
Configuración
Incluye la siguiente dependencia en tu archivo build.gradle:
Un ViewModel se utiliza para manejar algún estado. Todo ViewModel debe declarar las siguientes partes:
Variable de estado mutable (MutableStateFlow): define el estado que gestiona el ViewModel. Este estado es mutable y debe declararse privado para que los @Composable no puedan acceder al mismo directamente.
Variable de estado inmutable (StateFlow): Es una derivación inmutable del estado anterior, este es público ya que
Funciones de acciones del estado:
Ejemplo
Por ejemplo, podemos crear una aplicación para gestionar tareas (Task). Esta aplicación tendrá dos ventanas:
TasksScreen: Muestra un listado de tareas
CreateTaskScreen: Sirve para crear una nueva tarea.
Cada tarea la reprsentaremos con la data class Task
com.example.myApp.domain.model.Task.kt
data class Task(val id: Int, val title: String, val description: String)
TasksScreen
Esta ventana muestra una lista de tareas usando un LazyColumn. Para gestionar la lista de tareas crearemos TasksViewModel
import androidx.lifecycle.ViewModel
import com.example.myandroidapp.domain.model.Task
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class TasksViewModel : ViewModel() {
// Estado mutable que almacena el listado de tareas
private val _tasks = MutableStateFlow<List<Task>>(
listOf(
Task(1, "Tarea 1", "Esta tarea hace cosas"),
Task(2, "Tarea 2", "Esta tarea hace otras cosas"),
Task(3, "Tarea 3", "Esta tarea hace no hace nada"),
Task(4, "Tarea 4", "Bla bla bla"),
Task(5, "Tarea 5", "La ultima tarea")
)
)
// Version inmutable del estado anterior, es el estado que va a leer el UI
val tasks: StateFlow<List<Task>> = _tasks
// Elimina una tarea
fun removeTask(id: Int) {
// Quita la tarea con el id del parametro de la lista
_tasks.value = _tasks.value.filter { it.id != id }
}
}
Después usamos el ViewModel en la ventana TasksScreen
Primer creamos el ViewModel que gestiona los datos de una tarea
import androidx.lifecycle.ViewModel
import com.example.tasksapp.domain.model.Task
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class CreateTaskViewModel : ViewModel() {
// Estado mutable que almacena el listado de tareas
private val _task = MutableStateFlow<Task>(
Task(0, "", "")
)
// Version inmutable del estado anterior, es el estado que va a leer el UI
val task: StateFlow<Task> = _task
fun setTitle(title: String) {
_task.value = _task.value.copy(title = title)
}
fun setDescription(description: String) {
_task.value = _task.value.copy(description = description)
}
fun save() {
// TODO Aquí va la lógica para guardar la tarea
// Veremos qué se hace en el próximo tema
}
}
Ahora ya podemos usarlo en la ventana CreateTaskScreen