Flutter使用GetStorage时出现空值检查运算符错误,求解决方案
问题描述
在Flutter项目中结合GetStorage与Firebase Auth判断用户登录状态时,未登录会触发“Null Check Operator Used On a Null Value”错误,登录后运行正常。以下是Home页面代码:
import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:mobihub_2/Screens/main_login.dart'; import 'package:mobihub_2/Screens/navigationscreens.dart/add.dart'; import 'navigationscreens.dart/adds.dart'; import 'navigationscreens.dart/chat.dart'; import 'navigationscreens.dart/home2.dart'; import 'navigationscreens.dart/person.dart'; class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @override // ignore: library_private_types_in_public_api _HomeState createState() => _HomeState(); } class _HomeState extends State<Home> { final auth = FirebaseAuth.instance; int currentTab = 0; final List<Widget> screens = const [ Home2(), Chat(), Youradds(), Account(), ]; final PageStorageBucket bucket = PageStorageBucket(); Widget currentScreen = const Home2(); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey.shade100, body: PageStorage( bucket: bucket, child: currentScreen, ), floatingActionButton: FloatingActionButton( backgroundColor: const Color(0xFFFFDC3D), elevation: 2.5, onPressed: () { if(FirebaseAuth.instance.currentUser != null){ Navigator.push(context, MaterialPageRoute(builder: (context) => const AddItems())); }else{ Navigator.push(context, MaterialPageRoute(builder: (context) => MainLogin())); } }, child: const Icon( Icons.add, color: Colors.black, ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, bottomNavigationBar: BottomAppBar( color: Colors.white, shape: const CircularNotchedRectangle(), notchMargin: 10, child: SizedBox( height: 60, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ MaterialButton( highlightElevation: 0.0, highlightColor: Colors.white, hoverColor: Colors.white, hoverElevation: 0.0, minWidth: 40, onPressed: () { setState(() { currentScreen = const Home2(); currentTab = 0; }); }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.home, color: currentTab == 0 ? const Color(0xFFFFDC3D) : Colors.black, size: 25, ), Text( '', style: TextStyle( color: currentTab == 0 ? const Color(0xFFFFDC3D) : Colors.white), ) ], ), ), MaterialButton( highlightElevation: 0.0, highlightColor: Colors.white, hoverColor: Colors.white, hoverElevation: 0.0, minWidth: 40, onPressed: () { setState(() { if(FirebaseAuth.instance.currentUser != null){ currentScreen = const Chat(); currentTab = 1; }else{ Navigator.push(context, MaterialPageRoute(builder: (context) => MainLogin())); } }); }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.chat, color: currentTab == 1 ? const Color(0xFFFFDC3D) : Colors.black, size: 25, ), Text( '', style: TextStyle( color: currentTab == 1 ? const Color(0xFFFFDC3D) : Colors.white), ) ], ), ) ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ MaterialButton( highlightElevation: 0.0, highlightColor: Colors.white, hoverColor: Colors.white, hoverElevation: 0.0, minWidth: 40, onPressed: () { setState(() { if(FirebaseAuth.instance.currentUser != null){ currentScreen = const Youradds(); currentTab = 2; }else{ Navigator.push(context, MaterialPageRoute(builder: (context) => MainLogin())); } }); }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.favorite, color: currentTab == 2 ? const Color(0xFFFFDC3D) : Colors.black, size: 25, ), Text( '', style: TextStyle( color: currentTab == 2 ? const Color(0xFFFFDC3D) : Colors.white), ) ], ), ), MaterialButton( highlightElevation: 0.0, highlightColor: Colors.white, hoverColor: Colors.white, hoverElevation: 0.0, autofocus: false, minWidth: 40, onPressed: () { setState(() { if(FirebaseAuth.instance.currentUser != null){ currentScreen = Account(); currentTab = 3; }else{ Navigator.push(context, MaterialPageRoute(builder: (context) => MainLogin())); } }); }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.person, color: currentTab == 3 ? const Color(0xFFFFDC3D) : Colors.black, size: 25, ), Text( '', style: TextStyle( color: currentTab == 3 ? const Color(0xFFFFDC3D) : Colors.white), ) ], ), ) ], ) ], ), ), ), ); } }
问题根源
代码中List<Widget> screens在初始化阶段就创建了Chat、Youradds、Account这些组件,而这些组件内部大概率直接使用了FirebaseAuth.instance.currentUser!这类空断言操作符。未登录时currentUser为null,断言操作触发空检查错误。
解决办法
1. 延迟创建需要登录的页面组件
将固定的组件列表改为组件构建函数列表,仅在用户登录后才创建对应组件:
// 替换原有的screens列表 final List<Widget Function()> screenBuilders = [ () => const Home2(), () => const Chat(), () => const Youradds(), () => Account(), ];
修改按钮点击逻辑,登录后再构建组件:
// 以Chat按钮为例 onPressed: () { setState(() { final user = FirebaseAuth.instance.currentUser; if(user != null){ currentScreen = screenBuilders[1](); currentTab = 1; }else{ Navigator.push(context, MaterialPageRoute(builder: (context) => const MainLogin())); } }); },
2. 修复子组件的空安全问题
检查Chat、Youradds、Account页面中所有使用currentUser!的地方,替换为安全的空处理方式:
- 使用可选链
?:FirebaseAuth.instance.currentUser?.uid - 使用默认值
??:FirebaseAuth.instance.currentUser?.displayName ?? "匿名用户" - 用
FutureBuilder/StreamBuilder监听用户状态:
// Account页面示例 class Account extends StatelessWidget { const Account({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return FutureBuilder<User?>( future: FirebaseAuth.instance.authStateChanges().first, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } if (snapshot.data == null) { return const Center(child: Text("请先登录")); } return Column( children: [ Text("用户ID: ${snapshot.data!.uid}"), // 其他用户信息组件 ], ); }, ); } }
3. 全局统一处理登录状态(优化)
在App入口用StreamBuilder监听authStateChanges(),直接根据登录状态跳转页面,避免未登录时加载Home页面:
// main.dart示例 void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: StreamBuilder<User?>( stream: FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } return snapshot.data != null ? const Home() : const MainLogin(); }, ), ); } }
内容的提问来源于stack exchange,提问作者Mianseb
相关产品推荐
相关产品推荐

