Flutter中Cubit调用close后无法发射新状态的错误求助
解决Cubit调用getShopGift时的「Bad state: Cannot emit new states after calling close」错误
错误核心原因
这个错误的本质是Cubit实例已经被关闭(调用了close()方法),但后续异步代码仍尝试通过emit()发送新状态。
排查与修复方案
1. 在Cubit方法中增加关闭状态检查
在调用emit()的前后,先判断Cubit是否已关闭,避免无效的状态发送:
Future<void> getShopGift() async { if (isClosed) return; // 请求发起前检查 emit(ShopGiftLoading()); try { final response = await dio.get('/shop/gift'); if (isClosed) return; // 请求成功后再次检查 emit(ShopGiftSuccess(response.data)); } catch (e) { if (isClosed) return; // 捕获异常后检查 emit(ShopGiftError(e.toString())); } }
2. 排查Cubit的销毁时机
- 如果使用
BlocProvider.autoDispose,确认页面/组件是否在网络请求完成前就被销毁(比如用户快速返回上页),导致Cubit被自动dispose。 - 检查代码中是否存在手动调用
cubit.close()的逻辑,若有,确保所有调用getShopGift的操作都在Cubit关闭前执行。
3. 调整BlocProvider的作用域
如果Cubit是在子组件中通过BlocProvider创建的,当子组件销毁时Cubit也会被dispose。若父组件仍持有该Cubit引用并调用方法,就会触发错误:
- 修复:将BlocProvider移至更高层级的父组件,确保Cubit生命周期覆盖所有需要调用其方法的场景;使用
BlocProvider.value传递实例时,确认原实例未被关闭。
4. 结合Dio取消令牌终止无效请求
在Cubit关闭时主动取消未完成的Dio请求,避免请求完成后触发无效的状态发送:
CancelToken _cancelToken = CancelToken(); Future<void> getShopGift() async { if (isClosed) return; _cancelToken = CancelToken(); // 每次请求生成新令牌 emit(ShopGiftLoading()); try { final response = await dio.get('/shop/gift', cancelToken: _cancelToken); if (isClosed) return; emit(ShopGiftSuccess(response.data)); } catch (e) { // 请求被取消时直接返回,不发送错误状态 if (isClosed || e is DioError && e.type == DioErrorType.cancel) return; emit(ShopGiftError(e.toString())); } } @override Future<void> close() { _cancelToken.cancel('Cubit已关闭,终止请求'); // 关闭时取消请求 return super.close(); }
内容的提问来源于stack exchange,提问作者Eslam Elreedy
相关产品推荐
相关产品推荐

