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

Flutter Provider中检测Consumer数据更新及经纬度缓冲实现

How to Detect Consumer Data Updates & Add LatLng Validation Buffer in Flutter ChangeNotifier Provider

Hey there! Let's break down your two requirements with practical code adjustments based on your existing setup:

1. Detecting When Consumer Receives Updated Data

The ChangeNotifier + Consumer setup triggers a rebuild of the Consumer's builder whenever notifyListeners() is called in your Provider. To explicitly track when data updates, you have two straightforward approaches:

Option A: Track Changes Directly in the Consumer Builder

In your widget's state class, add variables to store the last seen coordinates, then compare them to new values in the Consumer:

// Inside your State class
double? _lastLat;
double? _lastLang;

// Then in your Consumer builder
Consumer<PuhserDataProvider>(builder: (context, data, child) {
  if (data.devicePusherData != null) {
    final lat = extractLat("${data.devicePusherData.gps}");
    final lang = extractLang("${data.devicePusherData.gps}");
    
    // Check if coordinates have changed
    if (lat != _lastLat || lang != _lastLang) {
      log.w("Coordinates updated: $lat, $lang");
      _lastLat = lat;
      _lastLang = lang;
    }

    return GoogleMap(/* ... your existing map code ... */);
  } else {
    return Container(
      height: MediaQuery.of(context).size.height * 0.8,
      width: double.infinity,
      child: const Center(child: CircularProgressIndicator()),
    );
  }
})

Option B: Optimize Provider to Avoid Unnecessary Notifications

Modify the Provider to only call notifyListeners() when GPS data actually changes—this reduces redundant rebuilds and acts as an update tracker:

void _setDeviceData(DevicePusherData devicePusherData) {
  final newGps = devicePusherData.gps;
  final oldGps = _devicePusherData?.gps;

  // Only update and notify if GPS data has changed
  if (newGps != oldGps) {
    this._devicePusherData = devicePusherData;
    log.w("New valid GPS received: $newGps");
    notifyListeners();
  }
}

2. Adding 5-Time Validation Buffer for LatLng Coordinates

To ensure you only update the Google Map after 5 consistent GPS readings, add a buffer queue in your PuhserDataProvider to track recent values and validate them before notifying listeners.

Modified Provider Code with Validation Buffer

import 'dart:convert';
import 'package:pusher_client/pusher_client.dart';
// Import your model classes (DevicePusherData, OBDPuhserData) here

class PuhserDataProvider extends ChangeNotifier {
  final Pusher pusher;
  Logger log = getLogger("PuhserDataProvider");

  DevicePusherData? _devicePusherData;
  DevicePusherData? get devicePusherData => _devicePusherData;

  OBDPuhserData? _obdPusherData;
  OBDPuhserData? get obdPusherData => _obdPusherData;

  // Buffer to store up to 5 recent GPS readings
  final List<String> _gpsValidationBuffer = [];
  static const int _requiredValidations = 5;

  PuhserDataProvider(String imei, String token, String pusherKey) 
      : pusher = Pusher(
          pusherKey,
          PusherOptions(
            cluster: 'eu',
            authEndpoint: AUTH_URL,
            auth: PusherAuth(headers: {
              'Authorization': 'Bearer $token',
              'Content-Type': 'application/json',
              'Accept': 'application/json'
            }))
        ) {
    Channel channel = pusher.subscribe('private-$imei-send');
    channel.bind('obd-event', (data) => _setOBDData(OBDPuhserData.fromJson(json.decode(data)[0])));
    channel.bind('deviceevent', (data) => _setDeviceData(DevicePusherData.fromJson(json.decode(data)[0])));
  }

  void _setDeviceData(DevicePusherData newDeviceData) {
    final newGps = newDeviceData.gps;
    _gpsValidationBuffer.add(newGps);

    // Keep buffer limited to 5 entries
    if (_gpsValidationBuffer.length > _requiredValidations) {
      _gpsValidationBuffer.removeAt(0);
    }

    // Check if all 5 entries in the buffer match the latest GPS
    final allReadingsMatch = _gpsValidationBuffer.every((gps) => gps == newGps);

    // Only update and notify if we have 5 consistent readings
    if (_gpsValidationBuffer.length == _requiredValidations && allReadingsMatch) {
      _devicePusherData = newDeviceData;
      log.w("GPS validated after 5 checks: $newGps");
      notifyListeners();
      // Clear buffer to start fresh for next validation cycle
      _gpsValidationBuffer.clear();
    }
  }

  void _setOBDData(OBDPuhserData obdPusherData) {
    this._obdPusherData = obdPusherData;
    notifyListeners();
  }
}

How This Works:

  • Every new deviceevent adds the GPS string to a buffer.
  • Once the buffer has 5 entries, we check if all are identical (adjust to proximity checks if minor variations are acceptable).
  • If 5 consistent readings are confirmed, we update the Provider data and trigger the Consumer to rebuild the Google Map.
  • The buffer resets after successful validation to start fresh for the next cycle.

Optional: Proximity Check Instead of Exact Matches

If you need to allow minor coordinate variations, replace the allReadingsMatch check with a distance threshold (e.g., 5 meters):

// Add a helper to calculate distance between LatLng points
double _calculateDistance(LatLng a, LatLng b) {
  // Use a package like geolocator for accurate distance calculation
  return Geolocator.distanceBetween(a.latitude, a.longitude, b.latitude, b.longitude);
}

// In _setDeviceData:
final newLat = extractLat(newGps);
final newLng = extractLang(newGps);
final newLatLng = LatLng(newLat, newLng);

final allReadingsCloseEnough = _gpsValidationBuffer.every((gps) {
  final lat = extractLat(gps);
  final lng = extractLang(gps);
  return _calculateDistance(LatLng(lat, lng), newLatLng) <= 5; // 5-meter threshold
});

内容的提问来源于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:05:20