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

Flutter集成Mapbox页面返回后崩溃,如何停止导航?

Flutter Mapbox返回页面崩溃的解决方案

问题背景

在集成Mapbox的Flutter项目中,通过Navigator.push跳转到带导航功能的RestaurantsMap页面后,返回原页面时应用崩溃,推测原因是返回时Mapbox的定位跟踪、图层资源或未完成的异步任务仍在运行,未被正确清理。

核心解决方案

1. 页面销毁时强制清理Mapbox资源

重写State的dispose方法,停止定位跟踪、移除Mapbox图层与数据源、释放控制器,彻底切断后台运行的资源:

@override
void dispose() {
  // 停止Mapbox定位跟踪
  controller?.stopMyLocationTracking();
  // 移除已添加的图层和数据源(忽略清理失败的异常)
  if (controller != null) {
    controller.removeLayer("lines").catchError((_) {});
    controller.removeSource("fills").catchError((_) {});
    // 释放控制器资源
    controller.dispose();
  }
  super.dispose();
}

2. 终止未完成的异步任务

initState中调用的initializeLocationAndSave是异步方法,页面销毁时可能仍在执行,需添加销毁标记避免后续操作触发错误:

  • 在State类中添加销毁状态标记:
bool _isDisposed = false;
  • 在dispose中标记页面已销毁:
@override
void dispose() {
  _isDisposed = true;
  // ... 其他清理代码
  super.dispose();
}
  • 修改initializeLocationAndSave方法,在关键异步步骤前检查状态:
void initializeLocationAndSave() async {
  Location _location = Location();
  bool? _serviceEnabled;
  PermissionStatus? _permissionGranted;

  _serviceEnabled = await _location.serviceEnabled();
  if (_isDisposed) return;
  if (!_serviceEnabled) {
    _serviceEnabled = await _location.serviceEnabled();
    if (_isDisposed) return;
  }

  _permissionGranted = await _location.hasPermission();
  if (_isDisposed) return;
  if (_permissionGranted == PermissionStatus.denied) {
    _permissionGranted = await _location.requestPermission();
    if (_isDisposed) return;
  }

  LocationData _locationData = await _location.getLocation();
  if (_isDisposed) return;
  LatLng currentLatLng = LatLng(_locationData.latitude!, _locationData.longitude!);

  sharedPreferences.setDouble('latitude', _locationData.latitude!);
  sharedPreferences.setDouble('longitude', _locationData.longitude!);
  if (_isDisposed) return;

  for (int i = 0; i < restaurants.length; i++) {
    if (_isDisposed) break;
    Map modifiedResponse = await getDirectionsAPIResponse(currentLatLng, i);
    if (_isDisposed) break;
    saveDirectionsAPIResponse(i, json.encode(modifiedResponse));
  }
}

3. 取消位置更新监听(可选)

如果使用了Location插件的实时位置监听,需在dispose中取消订阅:

// 在State类中声明订阅对象
StreamSubscription<LocationData>? _locationSubscription;

// 在初始化方法中启动监听(如果有)
_locationSubscription = _location.onLocationChanged.listen((data) {
  // 处理位置更新逻辑
});

// 在dispose中取消订阅
@override
void dispose() {
  _locationSubscription?.cancel();
  // ... 其他清理代码
  super.dispose();
}

修改后的完整_RestaurantsMapState关键代码片段

class _RestaurantsMapState extends State<RestaurantsMap> {
  // Mapbox相关
  LatLng latLng = getLatLngFromSharedPrefs();
  late CameraPosition _initialCameraPosition;
  MapboxMapController? controller; // 改为可空类型,避免未初始化时调用
  late List<CameraPosition> _kRestaurantList;
  List<Map> carouselData = [];

  // 轮播相关
  int pageIndex = 0;
  late List<Widget> carouselItems;
  bool _isDisposed = false;
  StreamSubscription<LocationData>? _locationSubscription;

  @override
  void initState() {
    super.initState();
    _initialCameraPosition = CameraPosition(target: latLng, zoom: 15);

    // 原有的初始化逻辑...

    initializeLocationAndSave();
  }

  void initializeLocationAndSave() async {
    Location _location = Location();
    bool? _serviceEnabled;
    PermissionStatus? _permissionGranted;

    _serviceEnabled = await _location.serviceEnabled();
    if (_isDisposed) return;
    if (!_serviceEnabled) {
      _serviceEnabled = await _location.serviceEnabled();
      if (_isDisposed) return;
    }

    _permissionGranted = await _location.hasPermission();
    if (_isDisposed) return;
    if (_permissionGranted == PermissionStatus.denied) {
      _permissionGranted = await _location.requestPermission();
      if (_isDisposed) return;
    }

    LocationData _locationData = await _location.getLocation();
    if (_isDisposed) return;
    LatLng currentLatLng = LatLng(_locationData.latitude!, _locationData.longitude!);

    sharedPreferences.setDouble('latitude', _locationData.latitude!);
    sharedPreferences.setDouble('longitude', _locationData.longitude!);
    if (_isDisposed) return;

    for (int i = 0; i < restaurants.length; i++) {
      if (_isDisposed) break;
      Map modifiedResponse = await getDirectionsAPIResponse(currentLatLng, i);
      if (_isDisposed) break;
      saveDirectionsAPIResponse(i, json.encode(modifiedResponse));
    }
  }

  // 原有的其他方法...

  @override
  void dispose() {
    _isDisposed = true;
    // 取消位置监听
    _locationSubscription?.cancel();
    // 停止Mapbox定位跟踪
    controller?.stopMyLocationTracking();
    // 清理Mapbox图层和数据源
    if (controller != null) {
      controller!.removeLayer("lines").catchError((_) {});
      controller!.removeSource("fills").catchError((_) {});
      controller!.dispose();
    }
    super.dispose();
  }

  // 原有的build方法...
}

内容的提问来源于stack exchange,提问作者Bart Stencil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 07:30:54