Contenido del curso
Arquitectura y Almacenamiento de Datos
Repositorios y Gestión de Datos
Capa de Presentación y Navegación
- 12

HomeScreen con ViewModel, StateFlow y Coil
Viendo ahora - 13

Primera app Android con Hilt, Retrofit y Room
09:58 min - 14

Implementación de Barra de Navegación Inferior en Android Compose
13:05 min - 15

Creación de un Detail Screen en Jetpack Compose para Android
25:49 min - 16

Formulario de preórdenes con SharedFlow en Compose
20:02 min - 17

Lista y sincroniza preórdenes con StateFlow
23:58 min
Optimización y Flexibilidad
HomeScreen con ViewModel, StateFlow y Coil
Resumen
Construir la capa de presentación en Android con Jetpack Compose implica conectar un ViewModel con composables que reaccionen a estados. Aquí aprendes a crear un ViewModel con Hilt, exponer un StateFlow y renderizar la pantalla home con Coil para imágenes, ideal si trabajas en arquitectura limpia con capas domain y data.
Cómo se estructura el ViewModel con Hilt y StateFlow
La capa de presentación arranca con un paquete presentation y una clase OrderViewModel que extiende ViewModel. Para que Hilt lo reconozca dentro de su grafo de dependencias, agregas la anotación @HiltViewModel y el constructor lleva @Inject con el OrderRepository como parámetro [01:05].
¿Qué hace @HiltViewModel? Registra el ViewModel en el grafo de Hilt para que pueda inyectar dependencias automáticamente, como el repositorio que necesitas para traer las órdenes.
El estado de la vista se modela con un data class llamado HomeState que contiene tres propiedades: isLoading (boolean inicializado en false), isError (boolean en false) y data como una lista vacía de órdenes. Esta separación te permite manejar carga, error y éxito sin mezclar lógica.
Cómo convertir un Flow en StateFlow observable
Dentro del ViewModel defines val homeState: StateFlow<HomeState> que toma el flujo del repositorio y lo transforma. La cadena queda así:
getOrders()devuelve unFlowdesde el repositorio.- Aplicas un
filterpara evitar emisiones repetidas si los datos no cambian. - Usas
mappara procesar elResulty manejarlo confold. - En el caso de éxito:
isLoading = false,isError = false,data = listaDeOrdenes. - En el caso de fallo:
isError = true,isLoading = false,data = emptyList().
Finalmente, conviertes el Flow en StateFlow con stateIn, pasando el viewModelScope, una política de inicio que detiene emisiones cinco segundos después de que nadie observe, y un valor inicial con isLoading = true [03:40].
Cómo se construye la pantalla home con Jetpack Compose
La pantalla principal vive en un composable llamado HomeScreen anotado con @Composable. Recibe dos parámetros: un Modifier y el OrderViewModel inyectado mediante hiltViewModel(). Para escuchar el estado, usas collectAsState() sobre homeState, lo que te entrega un State<HomeState> reactivo.
El renderizado se resuelve con un when sobre las tres condiciones del estado:
- Loading: una
ColumnconfillMaxSize, fondo deMaterialTheme.colorScheme.background, alineación centrada vertical y horizontal, y unCircularProgressIndicatorcon color primario. - Error: misma estructura de columna, pero con un
Textque avisa del fallo, alineado horizontalmente conModifier.align. - Éxito: una
LazyColumnque itera sobrestate.value.datay dibuja cada orden.
¿Para qué sirve collectAsState en Compose? Suscribe el composable al
StateFlowdel ViewModel y recompone la UI cada vez que el estado cambia, sin que tengas que gestionar listeners manualmente.
Cómo cargar imágenes remotas con Coil
Para mostrar la foto de cada orden necesitas la librería Coil 2.4, agregada al build.gradle del módulo app con la implementación específica para Compose [05:30]. Coil maneja descarga, caché y errores de red sin que tengas que escribir esa lógica.
Dentro del componente ItemView, defines un painter con rememberAsyncImagePainter, al que le pasas un ImageRequest.Builder configurado con:
- El contexto local obtenido con
LocalContext.current. - El
dataque es la URL de la imagen. - Un
placeholdercon un drawable de barra de progreso indeterminada. - Un fallback de error con un drawable como
StateNotifyError.
Luego usas el composable Image con contentScale = ContentScale.Crop, tamaño de 48 dp y Modifier.clip(CircleShape) para que se vea redonda.
Cómo diseñar el ItemView con preview en tiempo real
Cada orden se renderiza en un composable ItemView que recibe un objeto Order del Domain. Recuerda que la capa de presentación solo se comunica con Domain, nunca directamente con data. La estructura es un Row con fillMaxWidth, verticalAlignment = Alignment.CenterVertically y horizontalArrangement con espacios.
Dentro del row colocas:
- La imagen circular cargada con Coil.
- Una
ColumnconModifier.weight(1f)y padding de 16 dp que contiene dosText: el nombre del cliente con estilotitleLarge,maxLines = 1yoverflow = TextOverflow.Ellipsis, más el nombre del producto con estilobodyLarge. - Un
IconconIcons.AutoMirrored.Filled.ArrowForward, alineado al centro vertical y con padding de 16 dp al final.
Por qué usar @Preview acelera el desarrollo en Compose
Compose te permite anotar una función con @Preview(showBackground = true) para visualizar el composable sin ejecutar la app. Creas una función como ItemViewPreview que llama a ItemView con un Order hardcodeado (nombre de cliente, producto, total, URL de imagen) y Android Studio renderiza el resultado en el panel lateral [09:15].
¿Qué errores comunes aparecen al inyectar ViewModels con Hilt? Suelen faltar dos cosas: la anotación
@AndroidEntryPointenMainActivityy el@Inject constructoren el ViewModel. Sin ambas, el grafo de dependencias no se construye.
La LazyColumn final lleva un padding de 8 dp, fillMaxSize y un verticalArrangement con espacio de 12 dp entre ítems para que la lista respire. Con esto ya tienes la pantalla lista para mostrar órdenes traídas desde la base de datos local o remota.
¿Te animas a replicar este flujo en tu propio proyecto y compartir cómo te fue con la inyección de Hilt?