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

