# Localização e GPS

> Location (ao vivo), LocationService (background) e GPSThread (contínuo) — com as unidades certas.

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

# Localização e GPS

Três peças, para três necessidades. Os callbacks disparam **fora da paint thread** → volte com
`Component.onUI(...)`.

| Classe | Para |
|---|---|
| `Location` | leitura **ao vivo** (singleton — uma instância por vez) |
| `LocationService` | coleta em **background**, gravando em arquivo ("ler e limpar") |
| `GPSThread` | **rastreamento contínuo** com callbacks |

## `Location` — leitura ao vivo
```java
Location loc = new Location();          // abre o GPS (throws IOException)
try {
   if (loc.retrieveGPSData()) {         // false = sem sinal/erro
      double lat = Location.getLatitude();
      double lon = Location.getLongitude();
      double vel = Location.velocity;   // ⚠️ em NÓS (knots)
      if (vel != Location.INVALID) { ... }   // cheque INVALID antes de confiar
   } else {
      Debug.log(Location.lowSignalReason);
   }
} finally {
   loc.stop();                          // ⚠️ SEMPRE pare — esquecer drena bateria
}
```
Campos estáticos: `location` (`double[]` lat/lon), `velocity` (nós), `pdop`, `satellites`, `direction`,
`lastFix`, e o marcador `INVALID = Double.MIN_VALUE`.

## `LocationService` — coleta em background
Grava fixes num arquivo; você lê e o arquivo é apagado (padrão "ler e limpar"):
```java
LocationService.start();   // começa a coletar (no-op no desktop)
// … mais tarde …
List<LocationService.GPSLogEntry> fixes = LocationService.readAll();  // lê E apaga o arquivo
for (LocationService.GPSLogEntry e : fixes) {
   double vel = e.velocity;   // ⚠️ aqui em METROS POR SEGUNDO (m/s) — diferente de Location!
}
LocationService.stop();
```

## ⚠️ Unidades de `velocity` diferentes!
| Fonte | Unidade |
|---|---|
| `Location.velocity` (ao vivo) | **nós (knots)** |
| `GPSLogEntry.velocity` (histórico) | **metros por segundo (m/s)** |

Confundir as duas é um bug silencioso de conversão. Ambas usam `INVALID` para "sem leitura".

## `GPSThread` — rastreamento contínuo
```java
GPSThread gps = new GPSThread(
   true,                 // highPrecision: só GPS (false = GPS+célula+WiFi)
   2000,                 // intervalo em ms
   () -> Component.onUI(() -> label.setText(Location.getLatitude() + ", " + Location.getLongitude())),
   erro -> Debug.log("GPS erro: " + erro)
);                        // já inicia ao construir
// … ao sair da tela:
gps.stopGps();            // para e aguarda a thread encerrar
```

## Boas práticas
- **Sempre `stop()`/`stopGps()`** ao sair — GPS ligado **drena bateria**.
- Cheque `INVALID`/`pdop` antes de confiar na posição.
- Atenção às **unidades** de `velocity` (nós vs m/s).
- Callbacks voltam à UI com `onUI(...)`.

## Erros comuns
- Esquecer `stop()` → bateria drenada.
- Tratar `Location.velocity` como m/s (é **nós**).
- Confiar na posição sem checar `INVALID`.

## Veja também
- [LocationPicker](/docs/ui/widgets/locationpicker) · [Mapas](/docs/data-and-services/maps) · [Permissões por plataforma](/docs/platforms)
