Contenido del curso
Google Maps SDK
Servicios de Localización
- 7

Kotlin Flows para medir tiempo en Android
Viendo ahora - 8

Simulación de ubicación GPS en emulador y dispositivo Android
05:48 min - 9

Modelos de localización propios con Clean Architecture
08:36 min - 10

Callbacks de Android convertidos en Flows
14:50 min - 11

Inyección de dependencias para observar localización en Android
06:33 min - 12

LocationTracker con StateFlow para rastreo en Android
08:46 min - 13

State Flows para controlar localización y tiempo en Kotlin
10:00 min - 14

Configuración y pruebas de Location Tracker en Android
09:37 min
Integración Maps con Localización
Manejo de permisos
Integración cámara
- 23

Cómo guardar fotos en Android con PhotoHandler
11:59 min - 24

Conversión de Bitmaps a Byte Arrays con Extension Functions
05:58 min - 25

CameraViewModel con Hilt y StateFlow
08:40 min - 26

Configuración de métodos del ViewModel para gestión de cámara
09:40 min - 27

Integración de CameraX con Jetpack Compose en Android
14:23 min - 28

Creación de pantalla de previsualización de fotos con Jetpack Compose
08:44 min - 29

Galería de fotos en marcadores del mapa
11:55 min
Servicios en Android
Transmisiones en Android (Broadcast)
Kotlin Flows para medir tiempo en Android
Resumen
Controlar el tiempo en proyectos de localización en Android es la diferencia entre una app que drena la batería y una que emite datos con precisión. Aquí construirás un timer con Kotlin Flows que emite intervalos cada 200 milisegundos, ideal para desarrolladores Android que quieren dominar programación reactiva aplicada a geolocalización.
¿Cómo se estructura una clase Timer con Flows en Kotlin?
La idea es crear un singleton sencillo dentro de una carpeta domain que centralice la emisión de tiempo para todo el proyecto.
El punto de partida es un archivo Timer.kt declarado como object Timer, lo que garantiza una única instancia accesible desde cualquier parte del código [01:00]. Dentro de ese objeto vive la función timeAndEmits(), que devuelve un Flow<Duration> y se apoya en la clase Duration de Kotlin para manejar tiempo de forma tipada.
¿Qué es un Flow en Kotlin? Es la API de Kotlin para programación reactiva. Te permite emitir múltiples valores a lo largo del tiempo y reaccionar a ellos con operadores como
collect,onEachocombine.
¿Cómo funciona el flow builder con intervalos de 200 ms?
Dentro del flow builder se guarda un lastEmitTime con System.currentTimeMillis() para marcar el inicio. Luego entras a un while(true) que ejecuta un delay(200) y captura el currentTime en cada vuelta.
La diferencia entre currentTime y lastEmitTime se calcula como elapsedTime y se emite en formato milliseconds, que devuelve una instancia de Duration. Al final de cada iteración, lastEmitTime se actualiza con currentTime para que el siguiente ciclo mida el intervalo real transcurrido [02:30].
Este patrón es importante porque el operador delay no es exacto: en pruebas reales aparecen valores de 203 o 204 milisegundos en lugar de 200 clavados, y la lógica de elapsedTime te entrega la duración real, no la teórica [05:30].
¿Cómo activo un Flow desde la MainActivity?
Un Flow no emite nada hasta que alguien lo colecta. Eso se llama cold flow.
En la MainActivity usas lifecycleScope.launch { ... } para lanzar una corrutina ligada al ciclo de vida de la actividad. Dentro invocas Timer.timeAndEmits().collect { ... } y registras cada emisión con Log.d("FlowTimer", "Timer interval emit: $it").
¿Qué es un cold flow? Es un flow que solo empieza a producir valores cuando un operador terminal como
collectlo activa. Sincollect, el código del builder nunca se ejecuta.
¿Qué diferencia hay entre collect y launchIn?
Kotlin Flows tiene tres tipos de piezas que conviene distinguir:
- Builders: construyen la emisión, como
flow { }. - Operadores intermedios: transforman datos en tránsito, como
onEach,zip,combineoscan. - Operadores terminales: activan la emisión, como
collectolaunchIn.
La alternativa más limpia es encadenar Timer.timeAndEmits().onEach { Log.d(...) }.launchIn(lifecycleScope). Aquí onEach reacciona a cada emisión y launchIn actúa como terminal, evitando el bloque manual de launch { collect { } } [07:00].
¿Cómo combino dos Flows con scan y zip?
La parte interesante llega cuando necesitas mezclar tiempo con otra fuente de datos.
Imagina un segundo flow llamado randomFlow que emite un número aleatorio entre 0 y 100 cada segundo. Para combinarlo con el timer aplicas dos operadores en cadena:
scan(Duration.ZERO) { acumulador, value -> acumulador + value }: parte de cero y va sumando cada emisión de 200 ms, dándote el tiempo acumulado.zip(Timer.randomFlow) { time, random -> time to random }: empareja cada valor de tiempo con un número aleatorio en unPair.onEach { Log.d("zipFlow", "value: ${it.first}, random: ${it.second}") }: imprime ambos valores juntos.launchIn(lifecycleScope): activa la cadena.
Al ejecutar verás que las emisiones bajan de cada 200 ms a cada segundo. La razón es que zip espera a que ambos flows hayan emitido antes de combinar y entregar el par, así que la cadencia la marca el flow más lento [10:00].
kotlin object Timer { fun timeAndEmits(): Flow<Duration> = flow { var lastEmitTime = System.currentTimeMillis() while (true) { delay(200) val currentTime = System.currentTimeMillis() val elapsedTime = currentTime - lastEmitTime emit(elapsedTime.milliseconds) lastEmitTime = currentTime } } }
Con esta base ya puedes conectar el timer a los componentes de localización y controlar exactamente cuándo emitir coordenadas. ¿Qué cadencia usarías tú para tu app de tracking? Cuéntame en los comentarios.