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

google_maps_flutter标记无法更新问题求助(GetX Obx/setState无效)

Flutter GetX Obx + Google Map 标记更新不生效问题解决方案

问题描述

使用GetX的Obx组件在Google Map上展示地点标记列表,首次加载可正常显示所有标记,但清空标记列表并调用更新后,旧标记仍未从地图移除;手动调用setState()也无法同步最新标记列表。

核心问题分析

  1. HomePage重复创建控制器:build方法中每次调用Get.put(HomeController(...)),导致UI重建时重复创建/替换控制器实例,状态管理混乱。
  2. stationsList数据未清空:每次调用getStationLists时未清除旧站点数据,新请求数据被追加到旧列表,循环添加标记时包含旧数据。
  3. moveCamera方法冗余添加标记:每次调用moveCamera都会添加重复的"Current address"标记,造成标记冗余。

解决方案步骤

1. 修复控制器初始化逻辑

将控制器初始化移至initState,避免重复创建控制器:

class _HomePageState extends State<HomePage>
    with AutomaticKeepAliveClientMixin {
  late HomeController controller;

  @override
  void initState() {
    super.initState();
    // 仅在初始化时创建一次控制器
    controller = Get.put(HomeController(ApiRepository(ApiBaseHelper())));
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      appBar: AppBar(),
      body: SafeArea(
        child: Stack(
          children: [
            Obx(
              () => controller.isLoading.value
                  ? const AppLoader()
                  : GoogleMap(
                      onTap: (position) {
                        controller.customInfoWindowController.hideInfoWindow!();
                      },
                      mapToolbarEnabled: true,
                      initialCameraPosition: CameraPosition(
                          target: controller.mapMarkers.isEmpty
                              ? const LatLng(20.5937, 78.9629)
                              : LatLng(
                                  controller.mapMarkers.last.position.latitude,
                                  controller
                                      .mapMarkers.last.position.longitude),
                          zoom: 15.4736,
                          tilt: 59.440717697143555,
                          bearing: 5.55),
                      mapType: MapType.normal,
                      markers: controller.mapMarkers,
                      circles: {
                        Circle(
                            circleId: const CircleId("id"),
                            center: controller.currentLocation.value,
                            radius: controller.selectedRadius == "Select radius"
                                ? 50000.00
                                : double.parse(controller.selectedRadius) *
                                    1000,
                            fillColor: Colors.blue.shade200.withOpacity(0.5),
                            strokeColor: Colors.blue.shade100.withOpacity(0.1))
                      },
                      onMapCreated: (GoogleMapController mapController) async {
                        if (!controller.myMapController.isCompleted) {
                          controller.myMapController.complete(mapController);
                          controller.customInfoWindowController
                                  .googleMapController =
                              await controller.myMapController.future;
                        } else {
                          controller.customInfoWindowController
                              .googleMapController = mapController;
                        }
                      },
                    ),
            ),
            CustomInfoWindow(
              width: 50.w,
              controller: controller.customInfoWindowController,
            ),
          ],
        ),
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

2. 清空stationsList避免数据累积

在getStationLists方法开头清除旧站点数据,确保仅处理最新请求的站点:

void getStationLists(double latitude, double longitude, String radius) async {
  isLoading(true);
  currentLocation(LatLng(latitude, longitude));
  mapMarkers.clear();
  stationsList.clear(); // 新增:清空旧站点数据
  final marker = Marker(
    markerId: const MarkerId("Current Location"),
    position: LatLng(latitude, longitude),
    icon: BitmapDescriptor.defaultMarker,
  );
  mapMarkers.add(marker);
  try {
    var requestBody = {
      "latitude1": "$latitude",
      "longitude1": "$longitude",
      "meter": radius,
      "assetTypeName": "Car"
    };
    var data = await _repo.getStationsList(requestBody);
    if (data.data!.isNotEmpty) {
      stationsList.addAll(data.data!);
      for (var element in stationsList) {
        double latitude = double.parse(element.latitude!);
        double longitude = double.parse(element.longitude!);
        Uint8List markerIcon = await getBytesFromAsset(
            'assets/images/lnt_charger_marker.png', 100);
        final marker = Marker(
          markerId: MarkerId(element.groupName!),
          position: LatLng(latitude, longitude),
          icon: BitmapDescriptor.fromBytes(markerIcon),
          onTap: () {
            controller.customInfoWindowController.addInfoWindow!(
                element.groupSeq == null
                    ? Wrap(
                        children: [
                          Container(
                            decoration: BoxDecoration(
                                color: Colors.white,
                                borderRadius: BorderRadius.circular(16.0)),
                            child: Column(
                              mainAxisSize: MainAxisSize.max,
                              children: [
                                Padding(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Text(
                                    element.groupName!,
                                    style: TextStyle(
                                        fontSize: 10.sp,
                                        fontWeight: FontWeight.bold,
                                        color: AppColors.textColor),
                                  ),
                                ),
                                Padding(
                                  padding: const EdgeInsets.only(
                                      left: 8.0, bottom: 8.0),
                                  child: Text(
                                    element.location!,
                                    style: TextStyle(fontSize: 10.sp),
                                  ),
                                )
                              ],
                            ),
                          )
                        ],
                      )
                    : Wrap(children: [
                        Container(
                          width: 50.w,
                          decoration: BoxDecoration(
                              color: Colors.white,
                              borderRadius: BorderRadius.circular(16.0)),
                          child: Column(
                            children: [
                              Padding(
                                padding: const EdgeInsets.only(
                                    left: 8.0, right: 8.0, top: 8.0),
                                child: Text(
                                  element.groupName!,
                                  style: TextStyle(fontSize: 10.sp),
                                ),
                              ),
                              MaterialButton(
                                onPressed: () {},
                                child: Container(
                                  decoration: BoxDecoration(
                                      borderRadius:
                                          BorderRadius.circular(8.0),
                                      color: AppColors.primaryColor),
                                  child: const Padding(
                                    padding: EdgeInsets.all(8.0),
                                    child: Text(
                                      "Details",
                                      style: TextStyle(color: Colors.white),
                                    ),
                                  ),
                                ),
                              )
                            ],
                          ),
                        )
                      ]),
            LatLng(latitude, longitude));
          },
        );
        mapMarkers.add(marker);
      }
      moveCamera(latitude, longitude);
      isLoading(false);
      debugPrint("The no of markers is ${mapMarkers.length}");
    } else {
      isLoading(false);
      AppValidations.showToast("No charging stations found for the location");
    }
  } catch (e) {
    isLoading(false);
    AppValidations.showToast(e.toString());
  }
}

3. 移除moveCamera中的冗余标记

删除moveCamera中重复添加的"Current address"标记:

Future<void> moveCamera(double latitude, double longitude) async {
  final GoogleMapController controller = await myMapController.future;
  controller.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
    target: LatLng(latitude, longitude),
    zoom: 7.4736,
    tilt: 59.440717697143555,
    bearing: 5.55,
  )));
}

额外优化建议

  • 移除mapMarkers.refresh():Rx集合在clear()和add()操作后会自动触发Obx更新,无需手动调用。
  • 确保MarkerId唯一:使用站点的唯一标识(如element.groupSeq)作为MarkerId,避免因名称重复导致标记被覆盖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:45:34