Flutter向Firebase添加数据时出现StateError状态错误求助
解决Flutter Bloc/Cubit报错:Bad state: Cannot emit new states after calling close
核心问题分析
- Cubit提前关闭:点击添加按钮时,先调用
add方法(异步写入Firestore),紧接着执行widget.onSave()。如果onSave是关闭当前页面(如路由pop),会直接销毁BlocProvider并调用Cubit的close()方法;而Firestore写入完成后执行emit时,Cubit已处于关闭状态,触发报错。 - Firestore API误用:
FirebaseFirestore.collection.add()返回的是Future<DocumentReference>,你错误将其强制转换为StreamSubscription?,导致_streamSubscription是无效对象,后续close()时的cancel()操作存在潜在风险。
修复方案
1. 修正Cubit的Firestore调用逻辑
移除错误的StreamSubscription相关代码,因为add是单次写入操作,不需要监听流:
import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; part 'add_page_state.dart'; class AddPageCubit extends Cubit<AddPageState> { AddPageCubit() : super(const AddPageState()); Future<void> add( String product, String shopName, String category, ) async { try { // 直接执行Firestore写入,无需赋值给StreamSubscription await FirebaseFirestore.instance.collection('shoppingList').add( { 'product': product, 'shopName': shopName, 'category': category, }, ); emit(const AddPageState(saved: true)); } catch (error) { emit(AddPageState(errorMessage: error.toString())); } } @override Future<void> close() { return super.close(); } }
2. 调整页面按钮执行顺序
不要在调用add后立即执行onSave,而是监听Cubit状态变化,确认写入完成后再触发页面关闭:
BlocBuilder<AddPageCubit, AddPageState>( builder: (context, state) { // 监听saved状态,在帧绘制完成后执行onSave if (state.saved) { WidgetsBinding.instance.addPostFrameCallback((_) { widget.onSave(); }); } if (state.errorMessage.isNotEmpty) { return Center( child: Text('Someting went wrong ${state.errorMessage}!'), ); } return Center( child: Padding( padding: const EdgeInsets.all(25.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 原有输入组件保持不变 // ... ElevatedButton( onPressed: _product == null || _shopName == null ? null : () { context.read<AddPageCubit>().add( _product!, _shopName!, _category!, ); // 移除此处的widget.onSave() }, child: const Text('Dodaj'), ), ], ), ), ); }, )
3. 可选:优化状态类(提升扩展性)
给AddPageState添加copyWith方法,避免每次创建全新状态对象:
part of 'add_page_cubit.dart'; class AddPageState { const AddPageState({ this.saved = false, this.errorMessage = '', }); final bool saved; final String errorMessage; AddPageState copyWith({ bool? saved, String? errorMessage, }) { return AddPageState( saved: saved ?? this.saved, errorMessage: errorMessage ?? this.errorMessage, ); } }
后续emit状态时可简化为:
emit(state.copyWith(saved: true));
验证效果
修改后,点击添加按钮会先完成Firestore写入,emitsaved: true状态,再在页面帧绘制完成后执行onSave关闭页面。此时Cubit尚未被销毁,不会触发emit时的关闭状态错误,同时修正了Firestore API的误用问题。
内容的提问来源于stack exchange,提问作者Patryk
相关产品推荐
相关产品推荐

