Flutter Location包二次进入地图页面无法获取当前位置问题
问题分析
你的问题根源在于以下几点:
- 每次调用
getCurrentLocation都创建新的Location实例,且未在页面销毁时取消位置监听,导致资源泄漏,二次进入页面时监听逻辑异常。 currentLocation未做null安全处理,页面重建时可能还未获取到位置就强制解包,引发空指针问题(实际代码中此处会直接崩溃)。- 二次进入页面时,位置获取的异步流程未正确触发状态更新,导致
currentLocation始终为null。
修复方案
修改后的代码如下,关键改动已标注:
import "dart:async"; import "package:dayagreen/ui/widgets/app_bar.dart"; import "package:flutter/material.dart"; import "package:google_maps_flutter/google_maps_flutter.dart"; import "package:location/location.dart"; class ChargingStationScreen extends StatefulWidget { const ChargingStationScreen({Key? key}) : super(key: key); @override State<ChargingStationScreen> createState() => _ChargingStationScreenState(); } class _ChargingStationScreenState extends State<ChargingStationScreen> { final Completer<GoogleMapController> _controller = Completer<GoogleMapController>(); LocationData? currentLocation; BitmapDescriptor? markerIcon = BitmapDescriptor.defaultMarker; // 1. 将Location实例提升为成员变量,复用实例避免状态混乱 final Location _location = Location(); // 2. 保存位置监听订阅,用于页面销毁时取消 StreamSubscription<LocationData>? _locationSubscription; Future<void> getCurrentLocation() async { bool _serviceEnabled; PermissionStatus _permissionGranted; _serviceEnabled = await _location.serviceEnabled(); if (!_serviceEnabled) { _serviceEnabled = await _location.requestService(); if (!_serviceEnabled) { return; } } _permissionGranted = await _location.hasPermission(); if (_permissionGranted == PermissionStatus.denied) { _permissionGranted = await _location.requestPermission(); if (_permissionGranted != PermissionStatus.granted) { return; } } // 3. 先同步获取当前位置并更新状态 try { final locationData = await _location.getLocation(); setState(() { currentLocation = locationData; }); } catch (e) { print("获取当前位置失败: $e"); return; } // 4. 根据控制器状态设置监听,避免阻塞 if (_controller.isCompleted) { final googleMapController = await _controller.future; _setupLocationListener(googleMapController); } else { _controller.future.then(_setupLocationListener); } } // 抽离监听逻辑,复用代码并避免重复监听 void _setupLocationListener(GoogleMapController controller) { _locationSubscription?.cancel(); _locationSubscription = _location.onLocationChanged.listen((newLocation) { setState(() { currentLocation = newLocation; print(currentLocation!.latitude!); controller.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( zoom: 14.4746, target: LatLng(currentLocation!.latitude!, currentLocation!.longitude!), ), ), ); }); }); } void addCustomIcon() { BitmapDescriptor.fromAssetImage(const ImageConfiguration(), "assets/images/maps_current_location.png") .then( (icon) { setState(() { markerIcon = icon; }); }, ); } @override void initState() { // addCustomIcon(); super.initState(); getCurrentLocation(); } // 5. 页面销毁时取消监听,释放资源 @override void dispose() { _locationSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { // 6. 处理位置未获取到的情况,显示加载状态 if (currentLocation == null) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } return Scaffold( appBar: const MainAppbar( title: "Charging Station", ), body: GoogleMap( mapType: MapType.normal, initialCameraPosition: CameraPosition( target: LatLng(currentLocation!.latitude!, currentLocation!.longitude!), zoom: 14.4746, ), onMapCreated: (GoogleMapController controller) { if (!_controller.isCompleted) { _controller.complete(controller); } // 地图创建后直接更新到当前位置 if (currentLocation != null) { controller.animateCamera( CameraUpdate.newCameraPosition( CameraPosition( zoom: 14.4746, target: LatLng(currentLocation!.latitude!, currentLocation!.longitude!), ), ), ); } }, markers: { Marker( markerId: const MarkerId("current_position"), position: LatLng(currentLocation!.latitude!, currentLocation!.longitude!), icon: markerIcon!, ) }, ), ); } }
关键改动说明
- 复用
Location实例,避免每次创建新实例导致的状态混乱。 - 新增监听订阅管理,页面销毁时取消订阅,防止内存泄漏和重复监听。
- 优化位置获取流程,先同步获取当前位置再设置监听,确保页面加载时能快速显示位置。
- 处理位置未获取到的场景,显示加载指示器避免空指针崩溃。
- 优化地图控制器逻辑,确保二次进入页面时能正确绑定位置监听。
内容的提问来源于stack exchange,提问作者Rasyid Miftahul Ihsan
相关产品推荐
相关产品推荐

