如何计算两个GeoPoint间方位角?变量无法保留历史值问题排查
问题:方位角计算时新旧坐标始终一致,历史坐标无法持久化
开发逻辑为:从服务器获取经纬度点,用bearingLat和bearingLon存储上一次的坐标,driverLat和driverLon存储新接收的坐标,调用Geolocator.bearingBetween(driverLat!, driverLon!, bearingLat, bearingLon)计算方位角。但日志显示新旧坐标始终相同,手动验证函数逻辑无问题,核心问题是bearingLat和bearingLon无法保留上一次的坐标值。
经排查,每次触发Geofire.onKeyMoved时都会新建UpdateDrivers实例,导致类内的bearingLat和bearingLon每次都会被初始化为0,随后被赋值为当前坐标,完全无法保留历史值。
核心代码
class UpdateDrivers { MapController osmController; bool removeDriverIcon; String? removeDriverKey; double? driverLon; String? driverKey; double? driverLat; double bearingLat = 0; double bearingLon = 0; static const double twoPi = 2 * pi; UpdateDrivers({ required this.osmController, required this.removeDriverIcon, this.removeDriverKey, }); void updateAvailableDriversOnMap() async { if (removeDriverIcon) { await osmController.setStaticPosition([], removeDriverKey!); removeDriverIcon = false; removeDriverKey = null; } else { if (GeoFireAssistant.nearByAvailableDriversList.length > 0) for (NearByAvailableDrivers driver in GeoFireAssistant.nearByAvailableDriversList) { driverKey = driver.key!; driverLat = driver.latitude!; driverLon = driver.longitude!; double z = Geolocator.bearingBetween( driverLat!, driverLon!, bearingLat, bearingLon); print("heading $z"); bearingLat = driverLat!; bearingLon = driverLon!; if (z.isNegative) { z = (twoPi + z); } print("heading " + driverLat.toString() + ", " + driverLon.toString() + ", " + bearingLat.toString() + ", " + bearingLon.toString() + ", "); } } } }
调用代码
case Geofire.onKeyMoved: NearByAvailableDrivers nearByAvailableDrivers = NearByAvailableDrivers( map['key'], map['latitude'], map['longitude']); GeoFireAssistant.updateDriverNearByLocation( nearByAvailableDrivers); UpdateDrivers updateDrivers = UpdateDrivers( osmController: osmController, removeDriverIcon: false, ); updateDrivers.updateAvailableDriversOnMap(); break;
日志信息
I/flutter (13573): heading 27.77351097, 85.36021822, 27.77351097, 85.36021822, I/flutter (13573): heading 62.148877298990115 I/flutter (13573): heading 27.77351071, 85.36021885, 27.77351071, 85.36021885, I/flutter (13573): heading 62.14887839428785
解决方案
核心是让bearingLat和bearingLon的状态在多次调用间保留,不能每次初始化新实例,以下是三种可行方案:
方案1:复用同一个UpdateDrivers实例
在调用代码的作用域(比如State类)中提前创建实例,每次触发事件时复用:
// 在State类中定义成员变量 late UpdateDrivers updateDrivers; // 在initState中初始化一次 @override void initState() { super.initState(); updateDrivers = UpdateDrivers( osmController: osmController, removeDriverIcon: false, ); } // 触发事件时直接复用实例 case Geofire.onKeyMoved: NearByAvailableDrivers nearByAvailableDrivers = NearByAvailableDrivers( map['key'], map['latitude'], map['longitude']); GeoFireAssistant.updateDriverNearByLocation( nearByAvailableDrivers); updateDrivers.updateAvailableDriversOnMap(); break;
方案2:将历史坐标变量提升到外部
把bearingLat和bearingLon放在持有状态的父类/State中,通过参数传递给UpdateDrivers:
// 在State类中定义成员变量 double bearingLat = 0; double bearingLon = 0; // 修改UpdateDrivers类,接收外部坐标引用 class UpdateDrivers { MapController osmController; bool removeDriverIcon; String? removeDriverKey; double? driverLon; String? driverKey; double? driverLat; static const double twoPi = 2 * pi; double bearingLat; double bearingLon; UpdateDrivers({ required this.osmController, required this.removeDriverIcon, required this.bearingLat, required this.bearingLon, this.removeDriverKey, }); // 原有updateAvailableDriversOnMap逻辑不变 } // 调用时传入外部变量 case Geofire.onKeyMoved: NearByAvailableDrivers nearByAvailableDrivers = NearByAvailableDrivers( map['key'], map['latitude'], map['longitude']); GeoFireAssistant.updateDriverNearByLocation( nearByAvailableDrivers); UpdateDrivers updateDrivers = UpdateDrivers( osmController: osmController, removeDriverIcon: false, bearingLat: bearingLat, bearingLon: bearingLon, ); updateDrivers.updateAvailableDriversOnMap(); break;
方案3:使用单例模式实现UpdateDrivers
让UpdateDrivers全局只有一个实例,确保状态持久化:
class UpdateDrivers { static final UpdateDrivers _instance = UpdateDrivers._internal(); MapController osmController; bool removeDriverIcon; String? removeDriverKey; double? driverLon; String? driverKey; double? driverLat; double bearingLat = 0; double bearingLon = 0; static const double twoPi = 2 * pi; // 私有构造函数 UpdateDrivers._internal({ required this.osmController, required this.removeDriverIcon, this.removeDriverKey, }); // 工厂构造函数返回单例 factory UpdateDrivers({ required MapController osmController, required bool removeDriverIcon, String? removeDriverKey, }) { _instance.osmController = osmController; _instance.removeDriverIcon = removeDriverIcon; if (removeDriverKey != null) { _instance.removeDriverKey = removeDriverKey; } return _instance; } // 原有updateAvailableDriversOnMap逻辑不变 }
调用时直接获取单例即可,无需每次新建:
case Geofire.onKeyMoved: NearByAvailableDrivers nearByAvailableDrivers = NearByAvailableDrivers( map['key'], map['latitude'], map['longitude']); GeoFireAssistant.updateDriverNearByLocation( nearByAvailableDrivers); UpdateDrivers updateDrivers = UpdateDrivers( osmController: osmController, removeDriverIcon: false, ); updateDrivers.updateAvailableDriversOnMap(); break;
验证效果
修改后,bearingLat和bearingLon会保留上一次的坐标值,调用Geolocator.bearingBetween时能正确计算新旧坐标的方位角,日志中会显示不同的新旧坐标值。
内容的提问来源于stack exchange,提问作者Pannam
相关产品推荐
相关产品推荐

