Flutter程序抛出NotInitializedError问题排查求助
Flutter程序抛出NotInitializedError异常排查
开发的Flutter程序无法正常运行,抛出Instance of 'NotInitializedError'异常。原本推测问题出在getLocation()方法或SharedPreferences变量上,通过打印日志发现代码执行卡在loc.LocationData _locationData = await _location.getLocation();这一行。
问题代码
import 'package:flutter/material.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart' as lat; import 'package:location/location.dart' as loc; import 'package:shared_preferences/shared_preferences.dart'; import 'package:mapbox_gl/mapbox_gl.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; //besafe late SharedPreferences sharedPreferences; LatLng getCurrentLatLngFromSharedPrefs() { return LatLng(sharedPreferences.getDouble('latitude')!, sharedPreferences.getDouble('longitude')!); } void main() async{ runApp(const MyApp()); sharedPreferences =await SharedPreferences.getInstance(); const color2= Color(0xfb74093); } 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( title: 'BeSafe', theme: ThemeData( primarySwatch: Colors.pink, ), home: const MyHomePage(title: 'BeSafe'), debugShowCheckedModeBanner: false, ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late CameraPosition _initialCameraPosition; late MapboxMapController controller; static const List<String> imageList = [ "https://www.uber-assets.com/image/upload/f_auto,q_auto:eco,c_fill,w_1099,h_733/v1568070387/assets/b5/0a5191-836e-42bf-ad5d-6cb3100ec425/original/UberX.png", "https://www.uber-assets.com/image/upload/f_auto,q_auto:eco,c_fill,w_956,h_537/v1569012661/assets/19/dea9bc-88d6-461e-a233-17ed4d8cdc09/original/Taxi.png", "https://www.uber-assets.com/image/upload/f_auto,q_auto:eco,c_fill,w_956,h_537/v1571927853/assets/39/c1c2c7-61eb-4432-9bac-728b974207e7/original/cityscoot-icon-mobile.png" ]; void initState(){ super.initState(); initializeLocationandSave(); LatLng latlng= getCurrentLatLngFromSharedPrefs(); _initialCameraPosition=CameraPosition(target:latlng ,zoom:15); print("he"); } void initializeLocationandSave() async{ sharedPreferences = await SharedPreferences.getInstance(); loc.Location _location = loc.Location(); bool? _serviceEnabled; loc.PermissionStatus? _permissionGranted; _serviceEnabled = await _location.serviceEnabled(); if (!_serviceEnabled) { _serviceEnabled = await _location.requestService(); } _permissionGranted = await _location.hasPermission(); if (_permissionGranted == loc.PermissionStatus.denied) { _permissionGranted = await _location.requestPermission(); } print("yo"); loc.LocationData _locationData = await _location.getLocation(); print("bye"); sharedPreferences.setDouble('latitude',_locationData.latitude!); sharedPreferences.setDouble('longitude',_locationData.latitude!); LatLng currentlatlng= getCurrentLatLngFromSharedPrefs(); } _onMapCreated(MapboxMapController controller) async { this.controller=controller; } _onStyleLoadedCallback() async{ } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Stack( children: <Widget>[ MapboxMap( accessToken: dotenv.env['MAPBOX_ACCESS_TOKEN'] ,initialCameraPosition: _initialCameraPosition, onMapCreated: _onMapCreated, onStyleLoadedCallback: _onStyleLoadedCallback, myLocationEnabled: true, myLocationTrackingMode: MyLocationTrackingMode.TrackingGPS, minMaxZoomPreference: const MinMaxZoomPreference(14, 17), ), new Positioned( child:SizedBox( height: 60, ),), new Positioned( child: Padding( padding:EdgeInsets.only(left:30,right:30,top:30), child: SizedBox( height: 40, child: TextField( decoration: InputDecoration( contentPadding: const EdgeInsets.all(30.0), border: OutlineInputBorder( borderRadius: BorderRadius.circular(50.0), borderSide: BorderSide( width: 10), ), fillColor: Colors.white24, filled: true, ), )) ), ), Padding( padding:EdgeInsets.only(top: 556), child: CarouselSlider( options: CarouselOptions( enlargeCenterPage: true, enableInfiniteScroll: true, height: 200, autoPlay: true, ), items: imageList.map((e) => ClipRRect( borderRadius: BorderRadius.circular(8), child: Stack( fit: StackFit.expand, children: <Widget>[ Image.network(e, width: 1050, height: 300, fit: BoxFit.cover,) ], ) , )).toList(), ), ), ] , ), ); } }
错误栈信息
The following NotInitializedError was thrown building MyHomePage(dirty, state: _MyHomePageState#9417a): Instance of 'NotInitializedError' The relevant error-causing widget was: MyHomePage MyHomePage:file:///C:/Users/ali33/StudioProjects/besafe/lib/main.dart:35:19 When the exception was thrown, this was the stack: C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49 throw_ packages/flutter_dotenv/src/dotenv.dart 42:7 get env packages/besafe/main.dart 113:40 build packages/flutter/src/widgets/framework.dart 4919:27 build packages/flutter/src/widgets/framework.dart 4806:15 performRebuild packages/flutter/src/widgets/framework.dart 4977:11 performRebuild packages/flutter/src/widgets/framework.dart 4529:5 rebuild
问题分析与修复方案
1. 首要解决:NotInitializedError异常
从错误栈可以明确看到,异常来自flutter_dotenv的env未初始化。当前代码在main函数中直接先调用runApp,但没有先加载dotenv配置,导致MapboxMap组件在构建时访问dotenv.env['MAPBOX_ACCESS_TOKEN']时抛出未初始化异常。
修复方法:
在main函数中先初始化Flutter绑定,再加载dotenv配置,最后执行runApp和其他异步操作:
void main() async{ WidgetsFlutterBinding.ensureInitialized(); // 必须先初始化Flutter绑定 await dotenv.load(fileName: ".env"); // 加载.env文件,确保路径与项目中文件一致 sharedPreferences = await SharedPreferences.getInstance(); runApp(const MyApp()); const color2= Color(0xfb74093); }
2. 解决SharedPreferences空指针风险
当前initState中直接调用getCurrentLatLngFromSharedPrefs(),但此时initializeLocationandSave()是异步方法,SharedPreferences中还没有保存经纬度数据,或者全局变量sharedPreferences可能未完成初始化,会导致空指针异常。
修复方法:
- 在获取SharedPreferences中的经纬度时添加空值判断,提供默认坐标兜底:
LatLng getCurrentLatLngFromSharedPrefs() { double? lat = sharedPreferences.getDouble('latitude'); double? lng = sharedPreferences.getDouble('longitude'); return LatLng(lat ?? 37.7749, lng ?? -122.4194); // 替换为合适的默认坐标 }
- 在
initializeLocationandSave获取到定位后,更新UI的相机位置:
void initializeLocationandSave() async{ sharedPreferences = await SharedPreferences.getInstance(); loc.Location _location = loc.Location(); bool? _serviceEnabled; loc.PermissionStatus? _permissionGranted; _serviceEnabled = await _location.serviceEnabled(); if (!_serviceEnabled) { _serviceEnabled = await _location.requestService(); if (!_serviceEnabled) { // 用户拒绝开启定位服务,可添加弹窗提示 return; } } _permissionGranted = await _location.hasPermission(); if (_permissionGranted == loc.PermissionStatus.denied) { _permissionGranted = await _location.requestPermission(); if (_permissionGranted != loc.PermissionStatus.granted) { // 用户拒绝定位权限,可添加弹窗提示 return; } } print("yo"); try { loc.LocationData _locationData = await _location.getLocation(); print("bye"); sharedPreferences.setDouble('latitude',_locationData.latitude!); sharedPreferences.setDouble('longitude',_locationData.longitude!); // 修复此处错误:之前错误将latitude赋值给longitude setState(() { _initialCameraPosition = CameraPosition( target: LatLng(_locationData.latitude!, _locationData.longitude!), zoom:15 ); }); } catch(e) { print("获取定位失败:$e"); } }
3. 修复定位获取卡住的问题
定位卡在getLocation()通常有以下原因,对应修复方案:
- 定位权限未正确授予:上述代码已添加权限检查和用户拒绝后的处理逻辑
- 设备定位服务未开启:代码中已处理请求开启服务的逻辑
- 平台配置缺失:
- Android:在
AndroidManifest.xml中添加定位权限:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> - iOS:在
Info.plist中添加定位权限描述:<key>NSLocationWhenInUseUsageDescription</key> <string>需要获取您的位置信息以展示地图</string>
- Android:在
内容的提问来源于stack exchange,提问作者Ali Fakhreldin
相关产品推荐
相关产品推荐

