Flutter写入Firestore报Null check operator空值错误如何修复
向Firestore写入用户信息时
Null check operator used on a null value报错修复 报错现象
触发写入操作时抛出空检查操作符作用于空值的异常,堆栈定位到UserProvider的getUser取值逻辑:
══════ Exception caught by gesture ═══════════════════════════════════════════ The following _CastError was thrown while handling a gesture: Null check operator used on a null value When the exception was thrown, this was the stack #0 UserProvider.getUser package:webite/provider/user_provider.dart:11 #1 _AddMealState.build.<anonymous closure>
问题相关原始代码
页面构建逻辑
Widget build(BuildContext context) { final UserProvider userProvider = Provider.of<UserProvider>(context); return Scaffold( appBar: AppBar( elevation: 1.0, iconTheme: const IconThemeData( color: Colors.black, ), title: const Text( "Inventory", style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold), ), backgroundColor: Colors.white, ), body: SingleChildScrollView( child: Container( padding: const EdgeInsets.symmetric(vertical: 60.0, horizontal: 16.0), child: Column( children: <Widget>[ GestureDetector( onTap: () => _selectImage(context), child: Container( margin: const EdgeInsets.only(), width: MediaQuery.of(context).size.width, height: 210.0, decoration: BoxDecoration( image: DecorationImage( image: _file == null ? const NetworkImage( 'https://i.sstatic.net/l60Hf.png') as ImageProvider : MemoryImage(_file!), ), ), ), ), const SizedBox( height: 10, ), Container( padding: const EdgeInsets.only(top: 10), width: MediaQuery.of(context).size.width, margin: const EdgeInsets.symmetric(horizontal: 20), child: TextFieldInput( maxLines: 1, maxLength: TextField.noMaxLength, controller: _mealNameController, labelText: 'Meal Name', ), ), Container( padding: const EdgeInsets.only(top: 10), width: MediaQuery.of(context).size.width, margin: const EdgeInsets.symmetric(horizontal: 20), child: TextFieldInput( maxLines: 1, maxLength: TextField.noMaxLength, controller: _priceController, labelText: 'price', ), ), Container( padding: const EdgeInsets.only(top: 10), width: MediaQuery.of(context).size.width, margin: const EdgeInsets.symmetric(horizontal: 20), child: TextFieldInput( maxLines: 5, controller: _mealDescriptionController, labelText: 'Meal description', maxLength: 150, ), ), const SizedBox(height: 28.0), Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ mealSize(context), const SizedBox(height: 9.0), mealSize(context), const SizedBox(height: 9.0), mealSize(context), ], ), const SizedBox(height: 40.0), GestureDetector( onTap: () => addMenu(userProvider.getUser.name), child: const Button(btnText: "Add Food Item")), ], ), ), ), ); }
UserProvider原始代码
class UserProvider with ChangeNotifier { User? _user; final AuthController _authMethods = AuthController(); User get getUser => _user!; Future<void> refreshUser() async { User user = await _authMethods.getUserDetails(); _user = user; notifyListeners(); } }
问题根因
UserProvider中声明的_user为可空类型User?,但getUsergetter直接使用!操作符对_user做强制非空解包,未做任何空值前置判断- 点击按钮触发
addMenu逻辑时,_user还未完成初始化:要么是页面启动时未调用refreshUser()拉取用户数据,要么是拉取接口还未返回结果,此时_user值为null,强制解包直接触发报错
修复方案
1. 调整UserProvider的getter逻辑,消除强制解包风险
将直接强制解包的getter改为返回可空类型,从根源避免空值强制转换报错:
class UserProvider with ChangeNotifier { User? _user; final AuthController _authMethods = AuthController(); // 移除强制解包,返回可空User类型 User? get getUser => _user; Future<void> refreshUser() async { User user = await _authMethods.getUserDetails(); _user = user; notifyListeners(); } }
2. 提前触发用户数据加载
在依赖用户数据的页面初始化生命周期中,主动调用refreshUser()拉取用户信息,确保进入页面后尽早完成_user赋值:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of<UserProvider>(context, listen: false).refreshUser(); }); }
3. 调用处增加空值拦截
修改按钮点击逻辑,在访问用户属性前先做非空判断,数据未就绪时直接拦截操作:
GestureDetector( onTap: () { final currentUser = userProvider.getUser; // 用户数据未加载完成时不执行写入逻辑 if (currentUser == null) return; addMenu(currentUser.name); }, child: const Button(btnText: "Add Food Item") )
可选交互优化
可以在_user为null时给按钮展示加载态,禁止用户点击,从交互层避免异常触发。
内容的提问来源于stack exchange,提问作者Jabu
相关产品推荐
相关产品推荐

