Flutter中Provider状态管理出现Null检查错误求助
问题排查:Provider状态管理中ProfilePage获取appUser为空的问题
之前采用Provider状态管理的实现方式曾正常运行,但目前持续触发错误:Exception has occurred. CastError (Null check operator used on a null value)。经调试发现,账户创建后LoginUserProvider类中的_userModel已成功赋值,但在ProfilePage页面通过Consumer获取的appUser却为空值。
LoginUserProvider类代码
class LoginUserProvider extends ChangeNotifier { UserModel? _userModel; SharedPreferences? preferences; final FirebaseAuth _auth = FirebaseAuth.instance; DatabaseService databaseService = DatabaseService(); UserModel? get appUser => _userModel; set setLoginUser(UserModel user) { _userModel = user; notifyListeners(); } Future<void> saveDataToFirestore(Map<String, dynamic> data) async { User? firebaseUser = _auth.currentUser; if (firebaseUser == null) return; await databaseService .saveUserDataToFirebase(firebaseUser.uid, data) .whenComplete(() { _userModel = UserModel.fromJson(data); // setLoginUser = UserModel.fromJson(data); }); notifyListeners(); } }
首页标签页(MyStatefulWidget)代码
class MyStatefulWidget extends StatefulWidget { const MyStatefulWidget({super.key}); @override State<MyStatefulWidget> createState() => _MyStatefulWidgetState(); } class _MyStatefulWidgetState extends State<MyStatefulWidget> with SingleTickerProviderStateMixin { int _selectedIndex = 0; TabController? _tabController; final List<Widget> _widgetOptions = <Widget>[ const HomePage(), const BusinessPage(), const MySettingsPage() ]; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } @override void initState() { super.initState(); _tabController = TabController(initialIndex: _selectedIndex, vsync: this, length: 3); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), ), body: TabBarView( physics: const NeverScrollableScrollPhysics(), controller: _tabController, children: _widgetOptions), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.business), label: 'Business', ), BottomNavigationBarItem( icon: Icon(Icons.settings), label: 'Settings', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.amber[800], onTap: _onItemTapped, ), ); } }
设置页与个人资料页代码
class MySettingsPage extends StatelessWidget { const MySettingsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Settings'), centerTitle: true,), body: SingleChildScrollView( child: Column( children: [ ListTile( leading: const Icon(Icons.person,), title: const Text('User profile'), trailing: const Icon(Icons.arrow_forward_ios), onTap: (){ Navigator.push(context, MaterialPageRoute(builder: ((context) => const ProfilePage()))); }, ) ], ), ) ); } } class ProfilePage extends StatefulWidget { const ProfilePage({super.key}); @override State<ProfilePage> createState() => _ProfilePageState(); } class _ProfilePageState extends State<ProfilePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Profile Page'), centerTitle: true,), body: Consumer<LoginUserProvider>( builder: (context, value, child) { return ListView( children: [ ListTile( title: const Text('E-mail'), subtitle: Text(value.appUser!.email!), // 错误发生在此处:appUser为空 ) ], ); }, ) ); } }
问题原因与解决方案
1. Provider作用域不足
原因:如果LoginUserProvider没有在足够高的层级(如MaterialApp根节点)初始化,ProfilePage所在的导航栈可能不在Provider的作用域内,导致Consumer无法获取到正确的实例。
解决:在main.dart中确保Provider包裹在MaterialApp外层:
void main() { runApp( ChangeNotifierProvider( create: (context) => LoginUserProvider(), child: const MyApp(), ), ); }
2. 状态更新时机问题
原因:原代码中notifyListeners()在whenComplete外部调用,可能导致状态通知早于_userModel赋值完成。
解决:将notifyListeners()移到whenComplete内部,确保赋值完成后再通知监听:
Future<void> saveDataToFirestore(Map<String, dynamic> data) async { User? firebaseUser = _auth.currentUser; if (firebaseUser == null) return; await databaseService.saveUserDataToFirebase(firebaseUser.uid, data).whenComplete(() { _userModel = UserModel.fromJson(data); notifyListeners(); // 移至此处 }); }
3. 空安全处理缺失
原因:直接使用value.appUser!.email!强制解空,即使appUser临时为空也会崩溃。
解决:添加空值判断,避免强制解空:
builder: (context, value, child) { if (value.appUser == null) { return const Center(child: CircularProgressIndicator()); } return ListView( children: [ ListTile( title: const Text('E-mail'), subtitle: Text(value.appUser!.email ?? '未设置邮箱'), ) ], ); },
4. 页面拼写错误修正
代码中MySettinsPage为拼写错误,应改为MySettingsPage,避免页面路由异常。
内容的提问来源于stack exchange,提问作者Ktrel
相关产品推荐
相关产品推荐

