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
26:24 min - 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
Implementación final del PreOrderRepository
Resumen
Implementar el PreOrderRepository cierra la capa de data en una app Android construida con Clean Architecture, Room y Hilt. Aquí verás cómo orquestar el guardado remoto y local, mapear entidades hacia dominio y exponer el repositorio mediante inyección de dependencias para que tu capa de presentación lo consuma sin fricción.
Qué hace el PreOrderRepository en la capa de data
El repositorio actúa como puente entre el remote data storage y el local storage, decidiendo cuándo sincronizar con el servicio remoto y cuándo persistir localmente con Room.
Dentro de la carpeta data se crea la clase PreOrderRepositoryImpl, que implementa la interfaz PreOrderRepository definida en domain. El constructor recibe dos dependencias clave que luego Hilt inyectará: el remote data storage y el local storage. Esa separación permite que la lógica de negocio no sepa si los datos vienen de la red o de la base de datos.
¿Qué es un repositorio en Clean Architecture? Es la clase que centraliza el acceso a datos y oculta a la capa de dominio si la información viene de una API, de Room o de cualquier otra fuente.
Cómo guardar una preorden con savePreOrder y manejar el flag de sincronización
El método savePreOrder ejecuta primero el guardado remoto y luego decide cómo persistir localmente.
La secuencia funciona así:
- Se llama a
remote.savePreOrder(preOrder)y se captura la respuesta con unalsoque entrega unresult. - Se construye una
PreOrderEntitypara Room con elpreOrderId, elcustomerNamey elproduct. - Se agrega un flag booleano que indica si la sincronización remota fue exitosa.
- Se llama a
localStorage.savePreOrderInRoom(entity)para almacenarla.
Ese flag es la pieza que después permite reintentar el envío si la red falló. Si result fue exitoso, el flag queda en true; si no, queda en false y la preorden espera su retry.
Cómo recuperar las preórdenes locales y mapearlas a dominio
El método de lectura retorna las preórdenes guardadas en Room y las transforma a entidades de dominio. La cadena es directa: localStorage devuelve las preórdenes desde Room, se envuelve la operación en un Room caching para capturar excepciones y se aplica un map { it.toDomain() }.
Ese toDomain() vive en una clase de mappers. Es una static function que convierte una PreOrderEntity de base de datos en un PreOrder de dominio, copiando el id, el customerName, el product y el flag de sincronización. Sin ese mapper, la capa de domain quedaría acoplada a Room, y eso rompería la regla de dependencia.
¿Por qué mapear entidades de Room a dominio? Porque la capa de dominio debe ser independiente del framework. Si cambias Room por otra base de datos, solo ajustas los mappers, no el dominio.
Cómo eliminar y reintentar preórdenes desde el repositorio
El borrado y el retry son los dos métodos que cierran el ciclo de vida de una preorden offline.
Cómo funciona el delete por ID en Room
El deletePreOrder no retorna nada, así que se invoca directamente: localStorage.delete(id) sobre Room. Es la operación más simple del repositorio, pero crítica para mantener limpia la base local cuando una preorden ya cumplió su ciclo.
Cómo reintentar la sincronización con retry
El método retry toma una preorden que quedó marcada como no sincronizada y vuelve a intentar enviarla al servicio remoto:
- Llama a
remote.savePreOrder(preOrder)y guarda la respuesta en unval result. - Si la respuesta es exitosa, ejecuta un
updateen Room cargando la preorden por su ID. - Cambia el flag a
truepara reflejar que la sincronización ya ocurrió.
Esa lógica habilita un patrón offline-first: la app funciona aunque no haya conexión, y los datos se reconcilian cuando vuelve la red.
Cómo inyectar el repositorio con Hilt en el módulo de DI
Para que el repositorio esté disponible en toda la app, se registra en un módulo de Hilt dentro de la carpeta DI.
El módulo se llama RepositoryModule y lleva las anotaciones habituales de Hilt:
@Modulepara declararlo como módulo.@InstallIn(SingletonComponent::class)para que viva durante toda la app.@Providesy@Singletonen cada función que expone un repositorio.
Dentro del módulo se declaran dos provides. El primero entrega un OrderRepository recibiendo RemoteDataStorage y LocalStorage como parámetros. El segundo, idéntico en estructura, entrega un PreOrderRepository con esas mismas dos dependencias. Ambas fuentes ya tienen @Inject en su constructor, por lo que Hilt las resuelve automáticamente en el grafo de dependencias.
¿Para qué sirve @InstallIn(SingletonComponent::class)? Indica a Hilt que las dependencias de ese módulo viven mientras viva la aplicación, evitando crear múltiples instancias del mismo repositorio.
Con esa configuración queda cerrada la capa de data: tienes un repositorio que combina remoto y local, mapea entidades hacia dominio, soporta retry y se inyecta limpiamente. El siguiente paso natural es la capa de presentación y UI, donde estos repositorios se consumen desde ViewModels.
¿En tu app prefieres una estrategia offline-first como esta o sincronización en tiempo real? Cuéntame en los comentarios cómo manejas el flag de sincronización en tus repositorios.