使用Firebase实现登录逻辑时触发Bad state异常问题
解决Firebase Realtime Database的"Bad state: Cannot fire new event. Controller is already firing an event"错误
问题描述
执行用户创建操作时,调用ref.child('users/$id').set(...)触发以下异常,但用户数据仍能成功写入Firebase:
Exception has occurred. DartError: Bad state: Cannot fire new event. Controller is already firing an event
堆栈追踪指向database_reference_web.dart第51行的set方法,仅发生在用户不存在的正向创建场景中。
可能原因
该错误源于Firebase Web SDK的事件控制器在异步操作中的状态冲突,常见诱因:
- 复用同一个
DatabaseReference实例执行多次异步操作,导致内部事件流冲突 - 使用的Firebase SDK版本存在异步处理的已知bug
解决方案
方案1:每次操作创建新的DatabaseReference实例
避免复用类成员变量的ref,在每个方法内创建独立的引用实例:
class DatabaseOperations { static final FirebaseDatabase database = FirebaseDatabase.instance; Future<UserModel?> getUserByEmail(String username) async { final ref = FirebaseDatabase.instance.ref(); var response = await ref .child('users') .orderByChild('username') .equalTo(username) .once(); if (!response.snapshot.exists) { return null; } var userMap = Map<String, dynamic>.from(response.snapshot.value as Map); var user = UserModel.fromJson(userMap); return user; } Future<UserModel?> getUserById(String id) async { final ref = FirebaseDatabase.instance.ref(); var response = await ref.child('users').orderByChild('id').equalTo(id).once(); if (!response.snapshot.exists) { return null; } var user = UserModel.fromJson(response.snapshot.value as Map<String, dynamic>); return user; } Future<bool> addUser(UserModel user, BuildContext context) async { final ref = FirebaseDatabase.instance.ref(); if (await getUserByEmail(user.username!) != null) { if (context.mounted) { await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Error'), content: const Text('User already exists'), actions: <Widget>[ TextButton( onPressed: () { Navigator.of(context).pop(); }, child: const Text('OK'), ), ], ); }); } return false; } var id = Uuid().v4(); await ref.child('users/$id').set({'username': user.username, 'password': user.password}); return await getUserById(id) != null; } }
方案2:升级Firebase相关依赖版本
检查pubspec.yaml中的Firebase依赖,升级到最新稳定版(旧版本的异步处理bug已被修复):
dependencies: firebase_core: ^2.15.0 firebase_database: ^10.2.0
执行flutter pub upgrade完成依赖更新。
方案3:用runZonedGuarded捕获异常(临时规避)
如果暂时无法修改引用逻辑或升级SDK,可使用runZonedGuarded包裹set操作,避免异常阻断业务流程:
await runZonedGuarded(() async { await ref.child('users/$id').set({'username': user.username, 'password': user.password}); }, (error, stackTrace) { // 可在此记录错误日志,不影响后续流程 print('Set operation error: $error'); });
额外优化建议
- 禁止明文存储密码:使用哈希算法(如SHA-256)对密码加密后再存入数据库
- 优先使用Firebase Authentication替代自定义登录逻辑,更安全且无需手动处理用户存在性校验
内容的提问来源于stack exchange,提问作者Bohdan
相关产品推荐
相关产品推荐

