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
相关产品推荐
相关产品推荐

