# 定位与 GPS

> Location（实时）、LocationService（后台）与 GPSThread（持续）—— 附带正确的单位。

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

# 定位与 GPS

三个部件，对应三种需求。回调**在绘制线程之外**触发 → 请用
`Component.onUI(...)` 返回。

| 类 | 用途 |
|---|---|
| `Location` | **实时**读取（单例 —— 同一时刻只能有一个实例） |
| `LocationService` | 在**后台**采集，写入文件（“读取并清空”） |
| `GPSThread` | 带回调的**持续跟踪** |

## `Location` —— 实时读取
```java
Location loc = new Location();          // 打开 GPS（throws IOException）
try {
   if (loc.retrieveGPSData()) {         // false = 无信号/出错
      double lat = Location.getLatitude();
      double lon = Location.getLongitude();
      double vel = Location.velocity;   // ⚠️ 单位为节（knots）
      if (vel != Location.INVALID) { ... }   // 信任前先检查 INVALID
   } else {
      Debug.log(Location.lowSignalReason);
   }
} finally {
   loc.stop();                          // ⚠️ 务必停止 — 忘记会耗尽电池
}
```
静态字段：`location`（`double[]` 纬度/经度）、`velocity`（节）、`pdop`、`satellites`、`direction`、
`lastFix`，以及标记值 `INVALID = Double.MIN_VALUE`。

## `LocationService` —— 后台采集
将定位点写入文件；你读取后文件即被删除（“读取并清空”模式）：
```java
LocationService.start();   // 开始采集（在桌面端为空操作）
// … 稍后 …
List<LocationService.GPSLogEntry> fixes = LocationService.readAll();  // 读取并删除该文件
for (LocationService.GPSLogEntry e : fixes) {
   double vel = e.velocity;   // ⚠️ 此处单位为米每秒（m/s）— 与 Location 不同！
}
LocationService.stop();
```

## ⚠️ `velocity` 的单位不同！
| 来源 | 单位 |
|---|---|
| `Location.velocity`（实时） | **节（knots）** |
| `GPSLogEntry.velocity`（历史） | **米每秒（m/s）** |

混淆二者会造成隐蔽的单位换算 bug。两者都用 `INVALID` 表示“无读数”。

## `GPSThread` —— 持续跟踪
```java
GPSThread gps = new GPSThread(
   true,                 // highPrecision: 仅 GPS（false = GPS+基站+WiFi）
   2000,                 // 间隔（毫秒）
   () -> Component.onUI(() -> label.setText(Location.getLatitude() + ", " + Location.getLongitude())),
   erro -> Debug.log("GPS erro: " + erro)
);                        // 构造时即启动
// … 离开屏幕时：
gps.stopGps();            // 停止并等待线程结束
```

## 最佳实践
- 退出时**始终调用 `stop()`/`stopGps()`** —— GPS 开启会**耗尽电池**。
- 在信任位置之前检查 `INVALID`/`pdop`。
- 注意 `velocity` 的**单位**（节 vs m/s）。
- 回调用 `onUI(...)` 返回 UI。

## 常见错误
- 忘记 `stop()` → 电池耗尽。
- 把 `Location.velocity` 当作 m/s（它是**节**）。
- 不检查 `INVALID` 就信任位置。

## 另见
- [LocationPicker](/docs/ui/widgets/locationpicker) · [地图](/docs/data-and-services/maps) · [各平台权限](/docs/platforms)
