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

初始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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:36:07