Flutter 应用程序在将标记注入谷歌地图后崩溃

问题描述 投票:0回答:1

我的应用程序包含一个谷歌地图屏幕,我需要从 api 获取位置, 我的 viewModel 如下所示:

class MapViewModel extends ChangeNotifier {
    MapRepo repo = MapRepo();
    List<VendorBranchModel> branches = [];
    Set<Marker> markers = {};
    bool isMapLoading = true;

    setMapLoading(bool val) {
      isMapLoading = val;
      notifyListeners();
    }

    void prepareMarkers() {
      markers =  branches.map((branch) {
        return Marker(
          markerId: MarkerId(branch.id ?? ""),
          position: LatLng(branch.latitude ?? 0.0, branch.longitude ?? 0.0),
          infoWindow: InfoWindow(
            title: branch.englishBranchName,
            snippet: branch.phoneNumber,
          ),
        );
      }).toSet();
      setMapLoading(false);

    }

    Future<void> getBranchesAPI({ required Function(String?) onError}) async {
        setMapLoading(true);
        var response = await repo.getBranches(pageNumber: MapConstants.pageNumber,
            pageSize: MapConstants.pageSize ,body: {});
        response.when( success: (NetworkBaseModel response) async {
          if (response.isSuccess == true) {
            branches = response.data;
            prepareMarkers();
          }
        }, failure: (NetworkExceptions error) {
          onError(error.message);
          setMapLoading(false);

        });
    }
}

正在更新的屏幕如下所示:

 @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
        create: (BuildContext context) => viewModel
          ..getBranchesAPI(
              onError: (error) => ToastManager.showToast(error ?? "")
          ),
        child: Scaffold(
            body: Column(children: [
          CustomSearchView(
            onSearch: (keyword) {},
            onFilter: (filters) {
              filterRequest.orderFilter = filters;
              AppLogs.debugLog(filters.toJson());
            },
          ),
        Expanded(
            child: Consumer<MapViewModel>(
              builder: (context, viewModel, child) {
                return viewModel.isMapLoading
                    ? Center(child: CircularProgressIndicator())
                    : GoogleMapsScreen(markers: viewModel.markers);
              },
            ),
        )
        ])));

谷歌地图小部件如下:

class GoogleMapsScreen extends StatefulWidget {
  final Set<Marker> markers;
  GoogleMapsScreen({super.key, required this.markers});

  @override
  State<GoogleMapsScreen> createState() => _GoogleMapsScreenState();
}

class _GoogleMapsScreenState extends State<GoogleMapsScreen> {

  @override
  Widget build(BuildContext context) {
   return
      GoogleMap(initialCameraPosition:
      CameraPosition(target: widget.markers.isNotEmpty ? widget.markers.first.position : LatLng(33.8938, 35.5018)),
        markers: widget.markers,
      );
  }
}

每当 api 加载并且地图获取标记时,应用程序就会崩溃,并且不会出现错误消息。 而当发送空标记时,地图显示为空状态。

任何帮助都会很棒。

flutter google-maps
1个回答
0
投票

根据您的描述,听起来崩溃可能是由于在构建或渲染小部件本身时更新 GoogleMapsScreen 小部件中的标记造成的。如果更新 widget.markers 然后重新渲染,就会发生这种情况,从而导致小部件状态不一致。以下是一些步骤和改进,可帮助排查并可能解决此问题:

设置标记的初始状态:初始化 GoogleMapsScreen 时,确保标记集具有默认值,以避免任何意外的空值。此外,在更新标记时使用 setState 显式更新标记可能会很有用。

为 API 响应添加错误处理:在继续创建标记之前,确保来自 getBranchesAPI 的响应数据结构良好且有效。有时,格式错误的数据可能会导致意外问题,而没有明确的错误消息。

使用键处理标记状态:向 GoogleMapsScreen 添加唯一键,以在标记集更新时强制小部件正确重建。

以下是代码的调整部分以及这些建议:

  1. 修改 GoogleMapsScreen 以确保正确的标记状态处理 使用带有唯一键的 widget.markers 来强制重建,并在标记为空时设置默认位置。

    类 GoogleMapsScreen 扩展 StatefulWidget { 最终设置标记; GoogleMapsScreen({super.key, 必需 this.markers});

    @覆盖 状态 createState() => _GoogleMapsScreenState(); }

    类 _GoogleMapsScreenState 扩展状态 {

    @覆盖 小部件构建(BuildContext上下文){ 返回谷歌地图( 初始相机位置:相机位置( 目标:widget.markers.isNotEmpty ? widget.markers.first.position : LatLng(33.8938, 35.5018), // 如果没有标记则默认位置 Zoom: 10, // 根据需要调整缩放级别 ), 标记:widget.markers, key: ValueKey(widget.markers), // 使用 ValueKey 在标记更改时强制重建 ); } }

  2. 更新MapViewModel中的prepareMarkers以验证标记数据 在添加标记之前检查每个分支是否具有有效坐标,以避免因空数据或无效数据而崩溃。

    无效的prepareMarkers() { 标记 = 分支.where((分支) => 分支.纬度!= null && 分支.经度!= null).map((分支) { 返回标记( markerId: MarkerId(branch.id ?? ""), 位置:LatLng(分支.纬度??0.0,分支.经度??0.0), 信息窗口: 信息窗口( 标题:branch.englishBranchName ?? 《无名》, 片段:branch.phoneNumber ?? “没有电话”, ), ); }).toSet(); setMapLoading(假); }

  3. 添加调试以跟踪错误 在 getBranchesAPI 中添加调试行以捕获和记录否则可能不明显的意外问题。

    Future getBranchesAPI({ required Function(String?) onError}) async { setMapLoading(true); 尝试 { var 响应 = 等待 repo.getBranches( 页码:MapConstants.pageNumber, pageSize:MapConstants.pageSize, 身体: {}, ); 响应.when( 成功:(NetworkBaseModel 响应)异步 { if (response.isSuccess == true) { 分支=响应.数据; 准备标记(); } 别的 { onError("加载数据失败"); } }, 失败:(网络异常错误){ onError(错误消息); setMapLoading(假); }, ); } 捕获 (e) { onError("发生意外错误:$e"); setMapLoading(假); } }

  4. 检查消费者中的标记 在显示地图之前使用 Consumer 确保 viewModel.markers 不为空:

    展开( 孩子:消费者( 构建器:(上下文,视图模型,子级){ 如果(viewModel.isMapLoading){ 返回中心(子:CircularProgressIndicator()); } else if (viewModel.markers.isEmpty) { return Center(child: Text("没有可用的位置")); } 别的 { 返回 GoogleMapsScreen(标记:viewModel.markers); } }, ),

) 这种方法将有助于追踪任何问题并确保 GoogleMapsScreen 在渲染标记时具有一致且有效的数据。

© www.soinside.com 2019 - 2024. All rights reserved.