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
相关产品推荐
相关产品推荐

