Flutter接入Firebase Auth时登录状态首次不生效需热重载问题求助
问题根因
问题完全出在Profile页面的状态管理逻辑上,和Login页面没有关联:
- 异步监听未触发UI重建:
FirebaseAuth.instance.authStateChanges().listen是异步回调,你在回调里修改了_status等变量,但没有调用setState()通知Flutter刷新UI,所以页面首次渲染时用的是初始值_status = null,自然命中else分支;热重载会强制重建页面,此时变量已经被异步回调赋值,所以显示正常。 - 重复注册监听器导致内存泄漏:你把
userStatus()放在build()方法里调用,每次页面重绘都会新增一个监听事件,长期运行会出现内存泄漏、回调多次触发的问题。 - 初始状态判断逻辑有漏洞:
_status初始值为null,null == true的判断结果为false,首次渲染必然走未登录分支。
修复方案
修改Profile页面的代码即可解决问题:
class Profile extends StatefulWidget { const Profile({Key? key}) : super(key: key); @override _ProfileState createState() => _ProfileState(); } class _ProfileState extends State<Profile> { String? _email; DateTime? _creationTime; DateTime? _lastSignIn; bool? _status; // 定义监听订阅对象,用于页面销毁时取消监听 StreamSubscription<User?>? _authListener; @override void initState() { super.initState(); // 仅在页面初始化时注册一次监听 _authListener = FirebaseAuth.instance.authStateChanges().listen((event) { // 变量更新后调用setState通知UI刷新 setState(() { if (event == null) { _status = false; _email = null; _creationTime = null; _lastSignIn = null; } else { _status = true; _email = event.email; _creationTime = event.metadata.creationTime; _lastSignIn = event.metadata.lastSignInTime; } }); }); } @override void dispose() { // 页面销毁时取消监听,避免内存泄漏 _authListener?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { // 新增加载状态,避免状态未更新时闪现未登录界面 if (_status == null) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } return userForm(); } // 以下userForm、button方法保持原有逻辑不变即可 Widget userForm() { if (_status == true) { return Scaffold( appBar: defaultAppBar('Profile'), body: Center( child: ListView( padding: const EdgeInsets.all(20), children: [ Container( margin: const EdgeInsets.all(30), child: Text( 'Email: $_email', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold), ), ), Container( margin: const EdgeInsets.all(30), child: Text( 'Creation Time: $_creationTime', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold), ), ), Container( margin: const EdgeInsets.all(30), child: Text( 'Last Sign-In: $_lastSignIn', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold), ), ), const SizedBox(height: 45), button('Change password', 1), const SizedBox(height: 18), button('Change email', 2), const SizedBox(height: 18), button('Sign-out', 0), ], ), ), ); } else { return Center( child: ListView( padding: const EdgeInsets.all(14), children: <Widget>[ const SizedBox(height: 100), Container( margin: const EdgeInsets.all(30), child: const Center( child: Text( 'Please sign-in to use this Feature', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ), ), const SizedBox(height: 50), button('Login', 3), const SizedBox(height: 18), button('Register', 4), ], ), ); } } Widget button(String txt, int _nav) { Color? _color = const Color(0xFF20348F); if (_nav == 0) { _color = Colors.red; } return TextButton( style: TextButton.styleFrom( primary: _color, textStyle: const TextStyle( fontSize: 20, ), ), child: Text(txt), onPressed: () { if (_nav == 0) { FirebaseAuth.instance.signOut(); Navigator.pushAndRemoveUntil( context, MaterialPageRoute( builder: (BuildContext context) => const SelectUser(), ), (route) => false, ); } else { Navigator.push(context, MaterialPageRoute(builder: (contex) { if (_nav == 1) { return const EditPass(); } else if (_nav == 2) { return const EditEmail(); } else if (_nav == 3) { return const Login(); } else { return const Register(); } })); } }, ); } }
额外优化建议
如果多个页面都需要用到用户登录状态,建议把Auth监听放在根Widget层级,用Provider、Bloc这类状态管理工具统一管理用户状态,避免每个页面单独做监听,减少重复代码和出错概率。
内容的提问来源于stack exchange,提问作者Johnny Megg
相关产品推荐
相关产品推荐

