# Localización y GPS

> Location (en vivo), LocationService (background) y GPSThread (continuo) — con las unidades correctas.

Source: https://crossfly.dev/es/docs/data-and-services/device-location-gps — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Localización y GPS

Tres piezas, para tres necesidades. Los callbacks se disparan **fuera del paint thread** → vuelve con
`Component.onUI(...)`.

| Clase | Para |
|---|---|
| `Location` | lectura **en vivo** (singleton — una instancia a la vez) |
| `LocationService` | recolección en **background**, grabando en archivo ("leer y limpiar") |
| `GPSThread` | **rastreo continuo** con callbacks |

## `Location` — lectura en vivo
```java
Location loc = new Location();          // abre el GPS (throws IOException)
try {
   if (loc.retrieveGPSData()) {         // false = sin señal/error
      double lat = Location.getLatitude();
      double lon = Location.getLongitude();
      double vel = Location.velocity;   // ⚠️ en NUDOS (knots)
      if (vel != Location.INVALID) { ... }   // comprueba INVALID antes de confiar
   } else {
      Debug.log(Location.lowSignalReason);
   }
} finally {
   loc.stop();                          // ⚠️ SIEMPRE detén — olvidarlo drena la batería
}
```
Campos estáticos: `location` (`double[]` lat/lon), `velocity` (nudos), `pdop`, `satellites`, `direction`,
`lastFix`, y el marcador `INVALID = Double.MIN_VALUE`.

## `LocationService` — recolección en background
Graba fixes en un archivo; tú lees y el archivo se borra (patrón "leer y limpiar"):
```java
LocationService.start();   // empieza a recolectar (no-op en desktop)
// … más tarde …
List<LocationService.GPSLogEntry> fixes = LocationService.readAll();  // lee Y borra el archivo
for (LocationService.GPSLogEntry e : fixes) {
   double vel = e.velocity;   // ⚠️ aquí en METROS POR SEGUNDO (m/s) — ¡diferente de Location!
}
LocationService.stop();
```

## ⚠️ ¡Unidades de `velocity` diferentes!
| Fuente | Unidad |
|---|---|
| `Location.velocity` (en vivo) | **nudos (knots)** |
| `GPSLogEntry.velocity` (histórico) | **metros por segundo (m/s)** |

Confundir las dos es un bug silencioso de conversión. Ambas usan `INVALID` para "sin lectura".

## `GPSThread` — rastreo continuo
```java
GPSThread gps = new GPSThread(
   true,                 // highPrecision: solo GPS (false = GPS+celda+WiFi)
   2000,                 // intervalo en ms
   () -> Component.onUI(() -> label.setText(Location.getLatitude() + ", " + Location.getLongitude())),
   erro -> Debug.log("GPS erro: " + erro)
);                        // ya inicia al construir
// … al salir de la pantalla:
gps.stopGps();            // detiene y espera a que la thread termine
```

## Buenas prácticas
- **Siempre `stop()`/`stopGps()`** al salir — el GPS encendido **agota la batería**.
- Comprueba `INVALID`/`pdop` antes de confiar en la posición.
- Atención a las **unidades** de `velocity` (nudos vs m/s).
- Los callbacks vuelven a la UI con `onUI(...)`.

## Errores comunes
- Olvidar `stop()` → batería agotada.
- Tratar `Location.velocity` como m/s (es **nudos**).
- Confiar en la posición sin comprobar `INVALID`.

## Véase también
- [LocationPicker](/docs/ui/widgets/locationpicker) · [Mapas](/docs/data-and-services/maps) · [Permisos por plataforma](/docs/platforms)
