Contenido del curso
Implementación en MVVM
- 4

Navegación y pantallas de onboarding en Compose
26:17 min - 5

Grafo de navegación en Jetpack Compose
12:05 min - 6

Creación de ViewModels para Interacción en Onboarding de Apps
15:56 min - 7

View Models en Android: Gestión de la Lógica de Negocio y UI
17:20 min - 8

Hilt y SharedPreferences en ViewModels Android
29:30 min
Pantallas de Seguimiento
Networking y Datos
Persistencia Local
Funcionalidades Avanzadas
Lanzamiento de la APP
Serialización de objetos entre pantallas en Compose
Resumen
Pasar datos entre pantallas en Jetpack Compose se vuelve mucho más limpio cuando usas la anotación @Serializable. En esta sesión conectamos la TrackerOverviewScreen con la SearchScreenRoute enviando el nombre de la comida y la fecha como argumentos serializados, y construimos el componente TrackedFoodItem que muestra cada alimento registrado en la pantalla principal de un tracker de calorías en Android.
¿Por qué usar Serializable para navegar en Jetpack Compose?
La navegación en Compose permite mover datos a través de rutas o deep links, pero cuando necesitas enviar objetos más complejos, esos objetos deben ser serializables. Así, al navegar de la pantalla A a la pantalla B, la UI puede transformar los datos y mostrarlos correctamente sin perder información en el camino.
¿Qué es la anotación @Serializable en Kotlin? Es una marca que convierte una clase en un objeto que puede transformarse en un formato transportable (como JSON) para viajar entre pantallas, procesos o capas, y reconstruirse al llegar.
La recomendación es clara: usa serialización para navegar y persistir datos entre pantallas. No solo te sirve para tipos simples, también para objetos complejos.
¿Cómo defino una ruta serializable con propiedades?
Dentro de core/navigation está la clase de rutas. Como ya está marcada como @Serializable, la SearchScreenRoute deja de ser un object y pasa a ser una data class con las propiedades que viajarán [02:00]:
mealName: tipoString.dayOfTheMonth: tipoInt.month: tipoInt.year: tipoInt.
De esta forma, cada vez que naveguemos al search, garantizamos que llegan una comida y una fecha, justo lo que necesita el caso de uso.
¿Cómo paso los argumentos desde TrackerOverviewScreen?
En la TrackerOverviewScreen ajustamos la lambda de navegación para que reciba esos cuatro valores: un String y tres Int. Tienen que ser exactamente los mismos tipos que viajan por la ruta, si no, el compilador te detiene.
Al tocar el botón de add, pasamos mealName como string y state.date.dayOfTheMonth, monthValue y year como enteros. Así llegamos al search con todos los datos listos para guardar en base de datos el nombre y la fecha real, y no esa fecha quemada de 1/1/2022 que arrastrábamos antes [12:30].
¿Cómo recibo los argumentos en la pantalla destino?
En el composable de la ruta de search usamos un NavBackStackEntry para extraer los argumentos:
mealName = args.getString("MEAL_NAME") ?: "".dayOfTheMonth = args.getInt("DAY") ?: 0.month = args.getInt("MONTH") ?: 0.year = args.getInt("YEAR") ?: 0.
Si el dato existe, lo pasamos; si no, devolvemos un valor por defecto. Esos valores se inyectan a la SearchScreen y reemplazan los datos que antes estaban hardcodeados.
¿Cómo construyo el componente TrackedFoodItem?
El TrackedFoodItem es el composable que muestra cada comida guardada dentro de la home del tracker. Recibe un TrackedFood, una lambda onDeleteClick y un Modifier [05:30].
La estructura visual arranca con un Row que tiene varios modificadores apilados:
clipconRoundedCornerShapede 5 para esquinas redondeadas.paddingconspacingExtraSmall.shadowconelevationde 1.dp y unshaperedondeado.backgroundconMaterialTheme.colorScheme.surface.paddingend despaceMediumyheightde 100.dp.
Dentro del Row aplicamos horizontalArrangement = SpaceBetween y verticalAlignment = CenterVertically para distribuir los elementos.
¿Qué contiene cada TrackedFoodItem por dentro?
El ítem se compone así:
- Una imagen cargada con Coil desde la URL del alimento, con un placeholder de hamburguesa y un fallback de error igual.
- Una columna con el nombre de la comida y la cantidad junto con las calorías.
- Un ícono
Default.Closeclicable que dispara la lambdaonDeleteClickpara borrar el ítem. - Una
Rowcon tres llamadas al componenteNutrientInfopara mostrar carbs, proteins y fat.
Cada NutrientInfo recibe un name desde stringResource, un amount tomado del TrackedFood, una unidad en gramos, un amountTextSize de 15 o 16 sp, un unitTextSize de 12 sp y un nameTextStyle con MaterialTheme.typography.bodyMedium.
¿Cómo se ve la app reactiva en el emulador?
Después de integrar el TrackedFoodItem en la TrackerOverviewScreen y conectar la navegación, probamos el flujo completo desde el onboarding [16:40]. Configuramos un perfil con 34 años, 1.80 m, actividad alta, objetivo de ganar peso y una distribución de macros de 40 % carbohidratos, 30 % proteínas y 30 % grasas.
Al llegar a la home, todo arranca en cero porque aún no hay comidas registradas. Agregamos huevos revueltos en breakfast (140 kcal por 100 g, comimos 200 g) y un cup noodles en lunch (150 g).
¿Cómo se actualiza la UI cuando agrego una comida? El
ViewModelreacciona al insert en base de datos y emite el nuevo estado, lo que recompone laTrackerOverviewScreeny muestra calorías, macros y la fecha exacta del registro.
El resultado: 280 kcal en desayuno, 680 kcal en almuerzo, total de 960 sobre 1512 kcal del objetivo, con 96 g de carbohidratos, 40 g de proteínas y 40 g de grasa registrados en tiempo real. Al revisar la base de datos, los ítems quedan guardados con imagen, gramos, amount y la fecha correcta.
¿Qué otras formas existen para pasar datos entre pantallas?
La anotación @Serializable no es la única opción, aunque es la más compatible con Jetpack Compose. También puedes usar:
- SharedViewModel compartido entre composables de un mismo grafo.
- Parcelable para enviar objetos a través de
Bundle. - SavedStateHandle para sobrevivir a cambios de proceso.
Cada alternativa se acomoda según el caso, pero la serialización mantiene el tipado fuerte y se integra de forma natural con la API de navegación de Compose.
¿Qué objetos complejos te gustaría enviar entre pantallas con @Serializable en tu próximo proyecto?