You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中ErrorScreen定时返回后黑屏问题排查及优化方案咨询

问题分析与优化方案

问题原因

  1. 路由栈逻辑错误:你的ErrorScreen是直接作为BlocBuilder的返回结果渲染的,并没有通过Navigator.push加入路由栈。调用Navigator.pop(context)时,实际上是尝试弹出当前路由栈的顶部页面,但ErrorScreen不在栈中,导致pop后没有页面可展示,出现黑屏。
  2. Timer未做资源清理:initState中创建的Timer没有在组件销毁时取消,若ErrorScreen提前被销毁,Timer回调仍会执行,可能引发上下文失效的异常。

优化实现方案

方案一:通过Bloc状态自动切换(推荐)

利用Bloc的状态管理机制,在触发错误状态后自动延迟切换回登录状态,无需手动操作路由:

  1. 修改AuthCubit,在发送错误状态后延迟切换回AuthPrompt:
void showAuthError(String message) {
  emit(AuthError(message));
  // 延迟3秒切换回登录提示状态,确保Cubit未关闭再执行
  Future.delayed(const Duration(seconds: 3), () {
    if (!isClosed) {
      emit(const AuthPrompt());
    }
  });
}
  1. 将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的资源清理:

  1. 修改页面构建逻辑,用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()),
          );
        }
      },
    ),
  );
}
  1. 完善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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 09:20:39