如何在返回首页时持续发送Cubit状态?解决emit异常
问题分析与解决方案
错误原因
- Timer泄漏导致Cubit关闭后仍触发emit:你的
OfficeCubit启动了每秒执行的Timer.periodic,但未在Cubit被close时取消该定时任务。当Cubit因页面销毁/重建被关闭后,Timer仍会持续尝试发送状态,触发Bad state: Cannot emit new states after calling close异常。 - BlocProvider作用域错误:你在页面的
build方法内创建BlocProvider,导致页面重建或切换时,Cubit会被重复实例化或销毁,既无法实现跨页面状态传递,也会加剧Timer泄漏问题。
修复步骤
1. 给OfficeCubit添加销毁逻辑,取消Timer
修改OfficeCubit代码,重写close方法,在Cubit销毁时停止定时任务:
class OfficeCubit extends Cubit<OfficeStates> { OfficeCubit():super(firstState(master,room1,room2,hall1,hall2)){ pup(); } String? _now; Timer? _everySecond; static OfficeCubit get(context)=>BlocProvider.of(context); void pup () { s.prepareMqttClient(); _now=DateTime.now().second.toString(); _everySecond=Timer.periodic(Duration(seconds: 1), (Timer t) async { _now = DateTime.now().second.toString(); emit(firstState(master,room1,room2,hall1,hall2)); }); } // 重写close方法,销毁时取消Timer @override Future<void> close() { _everySecond?.cancel(); return super.close(); } }
2. 全局挂载BlocProvider,实现跨页面状态共享
修改main.dart,将BlocProvider放在MaterialApp外层,确保整个应用共享同一个OfficeCubit实例:
Widget build(BuildContext context) { return BlocProvider( create: (context) => OfficeCubit(), child: MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( appBarTheme: AppBarTheme( elevation: 30.0, backgroundColor: Colors.blueGrey[900], toolbarHeight: 60.0, centerTitle: true, titleTextStyle: TextStyle( color:Colors.white70, ) ), ), home: MyHomePage(), ), ); }
3. 修改页面UI代码,移除局部BlocProvider
页面内不再创建新的OfficeCubit实例,直接使用全局提供的实例:
Widget build(BuildContext context) { return BlocBuilder<OfficeCubit,OfficeStates>( builder: (BuildContext context, state){ var cubit = OfficeCubit.get(context); if (state is firstState){ return Scaffold(/* 你的页面内容 */); } else { return CircularProgressIndicator(); } }, ); }
额外注意事项
- 确保
firstState中的master、room1等变量是实时更新的,否则emit的状态无变化会导致UI不刷新。 - 其他页面如需监听Cubit状态,直接使用
BlocBuilder或BlocListener即可,无需重复创建BlocProvider。
内容的提问来源于stack exchange,提问作者Hagar Atef
相关产品推荐
相关产品推荐

