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

Flutter地图标记程序报错:null check operator空值使用,求解决方案

Flutter地图程序运行红屏:空值检查运算符使用错误

我编写了一个带标记的Flutter地图程序,代码在分析器中无报错,但在模拟器运行时出现红屏,提示“null check operator used in a null value”。此前还出现过“field cl has not been initialized”错误,多次修改代码仍未解决问题,相关代码如下:

import 'dart:async';

import 'package:flutter/material.dart';

import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

 void main() {
   runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
     ),
      home: const MapSample(),
    );
  }
}


class MapSample extends StatefulWidget {
  const MapSample({super.key});

  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  double posla = 0.0;
  double poslo = 0.0;
  String country = "0";
  String admin = "0";
   String local = "0";
   String sublocal = "0";
   String post = "0";
   String street = "0";

  static Position? cl;
  late var lat;
  late var long;
  late CameraPosition _kGooglePlex;
  Future getper() async {
    bool services;
   LocationPermission per = await Geolocator.checkPermission();

    services = await Geolocator.isLocationServiceEnabled();
   if (per == LocationPermission.denied) {
      per = await Geolocator.requestPermission();
      if (per == LocationPermission.always) {}
    }

    print("=========================");
    print(per);
     print("===========================");
     return per;
   }

   Future<Position?> getLatAndLong() async {
    cl = await Geolocator.getCurrentPosition().then((value) => value);
    lat = cl?.latitude;
    long = cl?.longitude;
    _kGooglePlex = CameraPosition(
        target: LatLng(lat, long), zoom: 12.4746, tilt: 45, bearing: 45);
     setState(() {});
    return cl;
  }

  @override
  void initState() {
    getper();
    getLatAndLong();
    super.initState();
 }

  final Completer<GoogleMapController> _controller =
      Completer<GoogleMapController>();
  late GoogleMapController gmc;
  Set<Marker> mymarker = {
    Marker(
       markerId: MarkerId("1"), position: LatLng(cl!.latitude, cl!.longitude))
  };
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(children: [
       _kGooglePlex == null
           ? CircularProgressIndicator()
           : Container(
              child: GoogleMap(
                markers: mymarker,
                 mapType: MapType.hybrid,
                initialCameraPosition: _kGooglePlex,
                onMapCreated: (GoogleMapController controller) {
                  gmc = controller;
                },
              ),
              height: 150,
              width: 500,
            ),
      Text('$posla'),
      Text('$poslo'),
      Text('$country'),
      Text('$admin'),
      Text('$local'),
      Text('$sublocal'),
      Text('$post'),
      Text('$street'),
      ElevatedButton(
          onPressed: () async {
            cl = await getLatAndLong();
            print("lat ${cl!.latitude}");
            print("Long ${cl!.longitude}");
            List<Placemark> placemarks =
                 await placemarkFromCoordinates(cl!.latitude, cl!.longitude);

            setState(() {
              posla = cl!.latitude;
              poslo = cl!.longitude;
              country = placemarks[0].country!;
              admin = placemarks[0].administrativeArea!;
              local = placemarks[0].locality!;
              sublocal = placemarks[0].subLocality!;
              post = placemarks[0].postalCode!;
              street = placemarks[0].street!;
            });
          },
           child: Text("إظهر الاحداثيات")),
      ElevatedButton(
          onPressed: () async {
           LatLng latLng = LatLng(31.042639, 29.964639);
            //   gmc.animateCamera(CameraUpdate.newLatLng(latLng));
            gmc.animateCamera(CameraUpdate.newCameraPosition(
                 CameraPosition(target: latLng, zoom: 10)));
          },
           child: Text("gotoalex"))
    ]));
  }
}

问题根源及修复方案

1. 初始化阶段空值访问

  • cl是可空静态变量,但初始化mymarker时直接用cl!.latitude强制解包,此时cl还未通过异步方法赋值,必然触发空值错误。
  • 修复:将mymarker初始化为空集合,等获取到位置后再动态添加标记。

2. _kGooglePlex初始化逻辑错误

  • 声明为late变量但未提前赋值,且_kGooglePlex == null的判断无效(late变量未初始化会直接抛错而非返回null)。
  • 修复:给_kGooglePlex设置默认初始坐标,避免初始化阶段报错。

3. 权限与位置获取的异步顺序问题

  • initState中未等待权限获取完成就调用位置获取方法,可能导致权限不足时位置获取失败。
  • 修复:在getLatAndLong中先等待权限检查结果,再执行位置获取逻辑。

4. 潜在空值风险未处理

  • placemarks[0]的属性直接用!强制解包、gmc未做空值判断就调用方法,都可能触发空值错误。
  • 修复:使用??设置默认值,添加空值判断后再执行操作。

修改后的完整代码

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MapSample(),
    );
  }
}

class MapSample extends StatefulWidget {
  const MapSample({super.key});

  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  double posla = 0.0;
  double poslo = 0.0;
  String country = "0";
  String admin = "0";
  String local = "0";
  String sublocal = "0";
  String post = "0";
  String street = "0";

  Position? cl;
  late CameraPosition _kGooglePlex;
  final Completer<GoogleMapController> _controller = Completer<GoogleMapController>();
  GoogleMapController? gmc;
  Set<Marker> mymarker = {};

  // 默认初始坐标
  final LatLng _defaultLocation = const LatLng(31.042639, 29.964639);

  Future<LocationPermission> getper() async {
    bool servicesEnabled = await Geolocator.isLocationServiceEnabled();
    if (!servicesEnabled) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('请开启位置服务')),
        );
      }
      return LocationPermission.denied;
    }

    LocationPermission per = await Geolocator.checkPermission();
    if (per == LocationPermission.denied) {
      per = await Geolocator.requestPermission();
    }
    return per;
  }

  Future<void> getLatAndLong() async {
    final permission = await getper();
    if (permission != LocationPermission.whileInUse && permission != LocationPermission.always) {
      // 权限不足时使用默认位置
      setState(() {
        _kGooglePlex = CameraPosition(
          target: _defaultLocation,
          zoom: 12.4746,
          tilt: 45,
          bearing: 45,
        );
        mymarker.add(const Marker(
          markerId: MarkerId("1"),
          position: _defaultLocation,
        ));
      });
      return;
    }

    try {
      cl = await Geolocator.getCurrentPosition();
      if (cl != null) {
        setState(() {
          _kGooglePlex = CameraPosition(
            target: LatLng(cl!.latitude, cl!.longitude),
            zoom: 12.4746,
            tilt: 45,
            bearing: 45,
          );
          mymarker.add(Marker(
            markerId: const MarkerId("1"),
            position: LatLng(cl!.latitude, cl!.longitude),
          ));
        });
      }
    } catch (e) {
      print('获取位置失败: $e');
      // 获取失败时使用默认位置
      setState(() {
        _kGooglePlex = CameraPosition(
          target: _defaultLocation,
          zoom: 12.4746,
          tilt: 45,
          bearing: 45,
        );
        mymarker.add(const Marker(
          markerId: MarkerId("1"),
          position: _defaultLocation,
        ));
      });
    }
  }

  @override
  void initState() {
    // 初始化默认地图位置
    _kGooglePlex = CameraPosition(
      target: _defaultLocation,
      zoom: 12.4746,
      tilt: 45,
      bearing: 45,
    );
    getLatAndLong();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(children: [
        Container(
          height: 150,
          width: double.infinity,
          child: GoogleMap(
            markers: mymarker,
            mapType: MapType.hybrid,
            initialCameraPosition: _kGooglePlex,
            onMapCreated: (GoogleMapController controller) {
              gmc = controller;
              _controller.complete(controller);
            },
          ),
        ),
        Text('$posla'),
        Text('$poslo'),
        Text('$country'),
        Text('$admin'),
        Text('$local'),
        Text('$sublocal'),
        Text('$post'),
        Text('$street'),
        ElevatedButton(
          onPressed: () async {
            await getLatAndLong();
            if (cl == null) return;

            print("lat ${cl!.latitude}");
            print("Long ${cl!.longitude}");
            List<Placemark> placemarks = await placemarkFromCoordinates(
              cl!.latitude,
              cl!.longitude,
            );

            if (placemarks.isNotEmpty) {
              setState(() {
                posla = cl!.latitude;
                poslo = cl!.longitude;
                country = placemarks[0].country ?? "未知";
                admin = placemarks[0].administrativeArea ?? "未知";
                local = placemarks[0].locality ?? "未知";
                sublocal = placemarks[0].subLocality ?? "未知";
                post = placemarks[0].postalCode ?? "未知";
                street = placemarks[0].street ?? "未知";
              });
            }
          },
          child: const Text("إظهر الاحداثيات"),
        ),
        ElevatedButton(
          onPressed: () async {
            if (gmc == null) return;
            const LatLng latLng = LatLng(31.042639, 29.964639);
            gmc!.animateCamera(CameraUpdate.newCameraPosition(
              CameraPosition(target: latLng, zoom: 10),
            ));
          },
          child: const Text("gotoalex"),
        )
      ]),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 00:24:53