Flutter中ErrorScreen定时返回后黑屏问题排查及优化方案咨询
问题分析与优化方案
问题原因
- 路由栈逻辑错误:你的
ErrorScreen是直接作为BlocBuilder的返回结果渲染的,并没有通过Navigator.push加入路由栈。调用Navigator.pop(context)时,实际上是尝试弹出当前路由栈的顶部页面,但ErrorScreen不在栈中,导致pop后没有页面可展示,出现黑屏。 - Timer未做资源清理:
initState中创建的Timer没有在组件销毁时取消,若ErrorScreen提前被销毁,Timer回调仍会执行,可能引发上下文失效的异常。
优化实现方案
方案一:通过Bloc状态自动切换(推荐)
利用Bloc的状态管理机制,在触发错误状态后自动延迟切换回登录状态,无需手动操作路由:
- 修改
AuthCubit,在发送错误状态后延迟切换回AuthPrompt:
void showAuthError(String message) { emit(AuthError(message)); // 延迟3秒切换回登录提示状态,确保Cubit未关闭再执行 Future.delayed(const Duration(seconds: 3), () { if (!isClosed) { emit(const AuthPrompt()); } }); }
- 将
ErrorScreen改为无状态组件,移除内部Timer逻辑:
class ErrorScreen extends StatelessWidget { const ErrorScreen(this.error, {super.key}); final String error; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey, body: Center( child: Text( error, style: const TextStyle(color: Colors.black, fontSize: 20), ), ), ); } }
此时BlocBuilder会根据AuthCubit的状态自动切换页面,3秒后自动回到登录表单,符合状态驱动UI的设计理念。
方案二:使用路由跳转展示ErrorScreen
若坚持用路由方式打开错误页,需调整跳转逻辑并完善Timer的资源清理:
- 修改页面构建逻辑,用
BlocListener监听错误状态并跳转:
Widget build(BuildContext context) { return BlocListener<AuthCubit, AuthState>( listener: (context, state) { if (state is AuthError) { Navigator.push( context, MaterialPageRoute(builder: (_) => ErrorScreen(state.message)), ); } }, child: BlocBuilder<AuthCubit, AuthState>( builder: (context, state) { if (state is AuthSuccess) { return buildSuccessScreen(state); } else if (state is AuthPrompt) { return _LoginForm(buildSuccessScreen); } else { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } }, ), ); }
- 完善
ErrorScreen的Timer管理,避免内存泄漏:
class ErrorScreen extends StatefulWidget { const ErrorScreen(this.error, {super.key}); final String error; @override State<ErrorScreen> createState() => _ErrorScreenState(); } class _ErrorScreenState extends State<ErrorScreen> { Timer? _autoPopTimer; @override void initState() { super.initState(); _autoPopTimer = Timer(const Duration(seconds: 3), () { Navigator.pop(context); }); } @override void dispose() { _autoPopTimer?.cancel(); // 组件销毁时取消Timer super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey, body: Center( child: Text( widget.error, style: const TextStyle(color: Colors.black, fontSize: 20), ), ), ); } }
这种方式下ErrorScreen被加入路由栈,pop后会回到之前的登录页面,不会出现黑屏。
内容的提问来源于stack exchange,提问作者MattPrash
相关产品推荐
相关产品推荐

