初始GPS关闭时Flutter地图申请权限后UI不更新问题
Flutter真实设备地图页面权限授予后UI不更新问题
问题现象
- 模拟器上运行完全正常;
- 真实Android设备上:
- 初始GPS关闭时,进入地图页面会请求位置权限,但授予权限后UI无更新/刷新,需手动点击刷新按钮才能显示当前位置;
- 初始GPS已开启时,无需申请权限,UI可正常刷新并显示当前位置。
相关代码
import 'dart:math'; import 'package:location/location.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:crimelogger/FetchData.dart'; import 'package:crimelogger/INSERTION.dart'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:geolocator/geolocator.dart'; class NewMapScreen extends StatefulWidget { Set<Marker> st={}; Set<Marker> _mark = {}; NewMapScreen.withSet(Set<Marker> l) { st=l; print("Set Consrcutro is called"); _mark.clear(); _mark=l; } @override State<NewMapScreen> createState() { print("Create State is called"); return _NewMapScreenState(); } } class _NewMapScreenState extends State<NewMapScreen> { MapType mT = MapType.normal; double lat = 20; double lon = 20; bool ready = false; Color cl = Colors.grey; GoogleMapController? mapController; bool buildnow=false; void initState() { print("Inside Init State"); super.initState(); print("Leaving Init State"); } Future<void> _onMapCreated(GoogleMapController controller) async { print("INSIDE ONMAP"); mapController = controller; print("CONTROLLER IS CALLED"); setState(() { mapController!.moveCamera(CameraUpdate.newLatLng(LatLng(lat, lon))); cl = Colors.green; UpdateUI(); }); print("Leaving Onmap"); } void UpdateUI() async { print("Inside UPDATE UI"); await getCurrentLocation(1); setState(() { print("INSIDE SET STATE OF UPDATEUI"); widget._mark=widget.st; widget._mark.add(Marker( markerId: MarkerId("abcd"), position: LatLng(lat, lon), icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueCyan), infoWindow: InfoWindow(title: "YOUR LOCATION"))); ready = true; mapController!.moveCamera(CameraUpdate.newLatLng(LatLng(lat, lon))); }); } void Refresh() { print("INSIDE REFRESH"); if (ready == true) { mapController!.moveCamera(CameraUpdate.newLatLng(LatLng(lat, lon))); UpdateUI(); } } Future<int> getCurrentLocation(int x) async { Location location = Location(); print("INSDE GETCURRENTLOCATION"); bool _serviceEnabled = await location.serviceEnabled(); if (!_serviceEnabled) { bool _serviceEnabled = await location.requestService(); if (!_serviceEnabled) { return 1; } } PermissionStatus _permissionGranted = await location.hasPermission(); if (_permissionGranted == PermissionStatus.denied) { _permissionGranted = await location.requestPermission(); if (_permissionGranted != PermissionStatus.granted) { return 1; } } final _locationData = await location.getLocation(); if (_locationData != null) { lon=_locationData!.longitude!; lat=_locationData!.latitude!;} return 1; print("LEAVING GETCURRENTLOCATION"); } void changeMap() { setState(() { mT = mT == MapType.normal ? MapType.satellite : MapType.normal; }); } void onPressed(LatLng l) { print(l.longitude); print(l.latitude); Timestamp t=Timestamp.now(); showModalBottomSheet( context: context, builder: (context) { return Container( height: 100, child: Padding( padding: const EdgeInsets.all(8.0), child: ElevatedButton( child: Text('Report Crime'), onPressed: () { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => new Insertion.withValues(l, t)) ); }, ), ), ); }); } Widget build(BuildContext context) { print("BUILD mapbuild IS CALLED"); return Column( children: [ Expanded( child: Container( child: GoogleMap( myLocationEnabled: true, initialCameraPosition: CameraPosition(target: LatLng(lat, lon), zoom: 1), mapType: mT, onMapCreated: _onMapCreated, markers: widget._mark, myLocationButtonEnabled: true, zoomControlsEnabled: true, onTap: onPressed, onLongPress: onPressed, ), ), ), Row( children: [ Expanded( child: FloatingActionButton( onPressed: changeMap, backgroundColor: Colors.green, child: const Icon(Icons.map, size: 10.0), ), ), Expanded( child: FloatingActionButton( onPressed: Refresh, backgroundColor: cl, child: const Icon(Icons.add_circle_outline, size: 10), )), ], ) ], ); } }
附加说明
- 一段视频展示模拟器上无论GPS初始状态如何,应用均正常运行;
- 另一段视频展示Android设备上授予权限后UI未更新,需手动点击刷新地图页面才能显示位置。
解决方案
1. 监听权限与位置服务状态变化
在initState中添加监听,当权限或位置服务状态改变时自动触发位置更新:
@override void initState() { super.initState(); Location location = Location(); // 监听位置实时变化 location.onLocationChanged.listen((LocationData currentLocation) { if (currentLocation != null) { setState(() { lat = currentLocation.latitude!; lon = currentLocation.longitude!; // 更新当前位置标记 widget._mark.removeWhere((marker) => marker.markerId.value == "abcd"); widget._mark.add(Marker( markerId: MarkerId("abcd"), position: LatLng(lat, lon), icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueCyan), infoWindow: InfoWindow(title: "YOUR LOCATION"))); mapController?.moveCamera(CameraUpdate.newLatLng(LatLng(lat, lon))); }); } }); // 监听权限变化 location.onPermissionChanged.listen((PermissionStatus status) { if (status == PermissionStatus.granted) { getCurrentLocation(1); } }); // 监听位置服务开关状态 location.onServiceStatusChanged.listen((bool isEnabled) { if (isEnabled) { getCurrentLocation(1); } }); }
2. 修复位置获取逻辑
给真实设备留足服务开启的延迟时间,避免提前获取位置失败:
Future<int> getCurrentLocation(int x) async { Location location = Location(); print("INSDE GETCURRENTLOCATION"); // 等待位置服务完全开启 bool serviceEnabled = await location.serviceEnabled(); while (!serviceEnabled) { serviceEnabled = await location.requestService(); if (!serviceEnabled) { return 1; } await Future.delayed(const Duration(milliseconds: 500)); } // 等待权限完全授予 PermissionStatus permissionGranted = await location.hasPermission(); while (permissionGranted == PermissionStatus.denied) { permissionGranted = await location.requestPermission(); if (permissionGranted != PermissionStatus.granted) { return 1; } await Future.delayed(const Duration(milliseconds: 500)); } // 获取当前位置 final locationData = await location.getLocation(); if (locationData != null) { lon = locationData.longitude!; lat = locationData.latitude!; } print("LEAVING GETCURRENTLOCATION"); return 1; }
3. 优化_onMapCreated执行逻辑
避免在同步setState中调用异步方法,确保位置获取完成后再更新UI:
Future<void> _onMapCreated(GoogleMapController controller) async { print("INSIDE ONMAP"); mapController = controller; print("CONTROLLER IS CALLED"); await UpdateUI(); setState(() { cl = Colors.green; mapController!.moveCamera(CameraUpdate.newLatLng(LatLng(lat, lon))); }); print("Leaving Onmap"); }
4. 修复StatefulWidget状态初始化问题
不要在Widget构造函数中直接修改状态,改为在State的initState中初始化:
class NewMapScreen extends StatefulWidget { final Set<Marker> initialMarkers; const NewMapScreen.withSet(this.initialMarkers, {super.key}); @override State<NewMapScreen> createState() => _NewMapScreenState(); } class _NewMapScreenState extends State<NewMapScreen> { late Set<Marker> _mark; @override void initState() { super.initState(); _mark = Set.from(widget.initialMarkers); // 其他初始化逻辑 } }
内容的提问来源于stack exchange,提问作者sushcodes
相关产品推荐
相关产品推荐

