跳转到正文
YGJoon 技术博客

Flutter 项目案例(三):定位请求的生命周期与失败降级

发布于:
·1.2k 字 · 约 3 分钟·作者:
拆解定位权限、地图 SDK 事件流、目标平台 传感器回退、后端区域解析和本地缓存,理解移动定位能力的完整生命周期。
Flutter 项目案例(三):定位请求的生命周期与失败降级文章封面
目录

一个定位请求不只是调用插件

定位状态容器负责恢复缓存的区域信息并订阅插件事件流。页面和请求层读取统一的区域状态,避免各自保存相互矛盾的位置数据。

定位请求应明确精度、单次或连续模式,以及是否需要地址反查。设备定位负责返回坐标,业务层再决定是否调用区域解析服务。

拿到经纬度后,应用调用区域解析接口,更新共享状态并异步保存缓存。这样插件只负责设备坐标,业务层则消费统一的 区域数据模型。

下面的示例把定位、区域解析与缓存分开,并用请求序号忽略已经过期的结果:

int _requestVersion = 0;

Future<void> refreshLocation() async {
  final version = ++_requestVersion;

  try {
    final position = await readPositionWithFallback();
    if (version != _requestVersion) return;

    final region = await regionRepository.resolve(position);
    if (version != _requestVersion) return;

    regionState.value = region;
    await regionCache.save(region);
  } on TimeoutException {
    if (version == _requestVersion) {
      regionState.value ??= cachedRegion;
    }
  } finally {
    await locationProvider.stop();
  }
}

超时和备用定位能力

单次定位请求设置 15 秒超时。默认使用高精度模式;首次失败或超时后可以尝试一次平台备用定位能力。回退只允许一次,避免失败事件反复重启定位。

高精度定位
    ↓ 失败或超时
尚未尝试回退?──是──→ 平台备用能力 重试一次
    │ 否
    ↓
停止插件、结束等待、显示失败提示

失败被当作可预期业务结果处理:停止定位、结束 Completer 并记录日志。这样页面可以继续使用缓存或默认城市,不会因为权限拒绝把整段启动流程变成未处理异常。

定位更新会影响多个页面

区域解析成功后,定位状态容器会通知首页和相关内容列表刷新。首页也可以先用缓存坐标或默认城市拉首屏,再由实时定位成功后的刷新替换附近数据。这个设计减少了首屏对 GPS 的硬等待。

需要留意数据范围:HTTP 拦截器当前会在所有请求上附带城市和经纬度头。定位上下文对附近推荐有用,但登录、支付或其他不需要位置的请求是否也应携带精确坐标,适合逐类确认并缩小范围。

生命周期和竞态边界

定位事件流在 onClose() 中取消订阅,并销毁插件;本地缓存读取和写入也单独捕获格式错误。设备验证时仍应覆盖这些情况:

特别是异步请求可能跨越一次超时重试;如果旧请求晚到,最好用请求序号区分新旧结果,避免旧回调完成新请求的等待器。

经验总结

先诚实说:地图定位 SDK 我自己的项目里没接过,这段是拆示例应用时逐行验证的。requestVersion 这套序号防旧回调的写法,我把核心逻辑摘出来用 dart 实际跑过:慢请求先发、快请求后到时,旧回调确实被丢弃,状态只保留最新结果,断言全过。超时后回退平台备用能力的思路我认同,但”只回退一次”这条要写进需求——失败事件反复重启定位能把电量吃光。另外 HTTP 拦截器给所有请求带经纬度头这个细节值得警惕:登录、支付请求不需要位置,精确坐标能少传就少传,合规和省流量都赚。

小结

定位链路可以拆成五步:检查权限、启动一次设备定位、处理错误及回退、调用区域解析服务、缓存并通知业务页面。把每一步的状态和失败结果写清楚,比单纯“请求定位”更容易维护,也方便在不同平台上定位问题。


分享这篇文章:


相关文章

上一篇
Flutter 项目案例(二):隐私同意、SDK 初始化与登录恢复
下一篇
Flutter 项目案例(四):首页数据解析、compute 与页面活跃状态