You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Provider:检测Consumer数据更新及经纬度缓冲传地图问询

解决方案:给GPS数据加缓冲,攒够5次再更新地图

首先,咱们得把缓冲逻辑放在PuhserDataProvider里处理,而不是在Consumer中——因为每次调用notifyListeners()都会触发Consumer重建,把缓冲逻辑移到Provider里能更高效地控制UI更新时机,同时也符合ChangeNotifier的设计思路。

步骤1:在Provider中添加缓冲相关变量

修改你的PuhserDataProvider类,加入存储经纬度缓冲的列表、目标缓冲数量,以及供UI读取的最终缓冲后经纬度:

class PuhserDataProvider extends ChangeNotifier {
  final Pusher pusher;
  Logger log = getLogger("PuhserDataProvider");
  DevicePusherData _devicePusherData;
  DevicePusherData get devicePusherData => _devicePusherData;
  OBDPuhserData _obdPusherData;
  OBDPuhserData get obdPusherData => _obdPusherData;

  // 新增缓冲相关变量
  List<LatLng> _latLngBuffer = [];
  static const int _requiredBufferCount = 5; // 需要收集的经纬度数量
  LatLng _bufferedTargetLatLng; // 缓冲完成后的目标经纬度
  LatLng get bufferedTargetLatLng => _bufferedTargetLatLng;

  // ... 原构造函数保持不变

  // 确保extractLat和extractLang能在这里调用(可以把这两个函数移到Provider里,或者设为全局函数)
  double extractLat(String gpsStr) {
    // 你的解析逻辑
  }

  double extractLng(String gpsStr) {
    // 你的解析逻辑(注意:建议把变量名从lang改成lng,对应longitude的缩写,避免混淆)
  }

步骤2:修改数据更新方法,加入缓冲逻辑

更新_setDeviceData方法,每次收到新GPS数据时先存入缓冲,攒够5次后再计算最终位置并通知UI:

_setDeviceData(DevicePusherData devicePusherData) {
    this._devicePusherData = devicePusherData;
    
    // 解析当前经纬度
    final lat = extractLat("${devicePusherData.gps}");
    final lng = extractLng("${devicePusherData.gps}");
    final newLatLng = LatLng(lat, lng);
    
    // 添加到缓冲列表
    _latLngBuffer.add(newLatLng);
    
    // 检查缓冲是否达到要求数量
    if (_latLngBuffer.length >= _requiredBufferCount) {
      // 这里提供两种处理方式,按需选择:
      // 方式1:直接取最后一次的经纬度(简单直接)
      _bufferedTargetLatLng = _latLngBuffer.last;
      
      // 方式2:计算5次经纬度的平均值(平滑位置波动,适合高速移动场景)
      // double avgLat = _latLngBuffer.map((pos) => pos.latitude).reduce((a, b) => a + b) / _requiredBufferCount;
      // double avgLng = _latLngBuffer.map((pos) => pos.longitude).reduce((a, b) => a + b) / _requiredBufferCount;
      // _bufferedTargetLatLng = LatLng(avgLat, avgLng);
      
      // 清空缓冲,准备下一轮收集
      _latLngBuffer.clear();
      
      // 通知Consumer更新UI(这一步才会触发地图重建)
      notifyListeners();
    }
  }

步骤3:修改Consumer,监听缓冲后的经纬度

现在Consumer只需要监听bufferedTargetLatLng,只有当缓冲完成时才会重建地图:

Consumer<PuhserDataProvider>(builder: (context, data, child) {
  if (data.bufferedTargetLatLng != null) {
    final targetPos = data.bufferedTargetLatLng;
    log.w(targetPos.latitude);
    log.w(targetPos.longitude);
    return GoogleMap(
      onMapCreated: (GoogleMapController controller) {
        _controller.complete(controller);
      },
      myLocationButtonEnabled: false,
      initialCameraPosition: CameraPosition(
        target: targetPos,
        zoom: 16,
      ),
      markers: {
        Marker(
          markerId: const MarkerId('0'),
          position: targetPos,
          onTap: () => setState(() => selectedPoint = targetPos)
        )
      },
      onTap: (point) => setState(() => selectedPoint = null),
    );
  } else {
    return Container(
      height: MediaQuery.of(context).size.height * 0.8,
      width: double.infinity,
      child: const Center(child: CircularProgressIndicator()),
    );
  }
}),

额外说明

  • 关于检测数据更新:ChangeNotifier的notifyListeners()是触发Consumer重建的核心,只要Provider调用这个方法,Consumer就会感知到数据变化并重新执行builder函数。我们通过控制这个方法的调用时机,实现了“攒够5次再更新”的需求。
  • 如果需要初始位置显示:可以在Provider初始化时,或者第一次收到数据时,直接设置_bufferedTargetLatLng并调用notifyListeners(),避免用户一开始看到加载动画。

内容的提问来源于stack exchange,提问作者Javeed Ishaq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:07:09