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

Flutter使用Cubit检测网络时出现黑屏闪烁问题求助

解决Flutter中ConnectivityCubit弹窗前黑屏闪烁问题

在Flutter项目中使用ConnectivityCubit检测网络连接状态,无网络时弹出AlertDialog提示用户,但弹窗出现前屏幕会短暂黑屏闪烁,该如何避免?

原代码

main.dart

void main() {
  runApp(BlocProvider(
    create: (BuildContext context) => ConnectivityCubit()..checkConnectivity(),
    lazy: false,
    child: MaterialApp(home: MyApp()),
  ));
}

class MyApp extends StatelessWidget {
  MyApp({super.key});
  bool _isDialogDisplayed = false;
  @override
  Widget build(BuildContext context) {
    return BlocConsumer<ConnectivityCubit, ConnectivityState>(
      listener: (context, state) {
        if (state == ConnectivityState.disconnected) {
          _isDialogDisplayed = true;
          showDialog(
            context: context,
            builder: (context) => const AlertDialog(
              title: Text('No Internet'),
              content: Text('Please check your internet connection.'),
            ),
          );
        }
        if (state == ConnectivityState.connected &&
            _isDialogDisplayed == true) {
          Navigator.of(context).pop();
          _isDialogDisplayed = false;
        }
      },
      builder: (context, state) {
        if (state == ConnectivityState.init) {
          return const CircularProgressIndicator();
        }

        return MaterialApp(     //   <-- 问题根源
          home: Scaffold(                         
            body: state == ConnectivityState.connected
                ? const Center(
                    child: Text('Hello World'),
                  )
                : const Center(child: CircularProgressIndicator()),
          ),
        );
      },
    );
  }
}

cubit.dart

import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

enum ConnectivityState { connected, disconnected, init }

class ConnectivityCubit extends Cubit<ConnectivityState> {
  final Connectivity _connectivity = Connectivity();
  StreamSubscription<ConnectivityResult>? _subscription;
  late Stream<ConnectivityResult> streamValue;
  ConnectivityCubit() : super(ConnectivityState.init) {
    streamValue = _connectivity.onConnectivityChanged;
    _subscription = _connectivity.onConnectivityChanged.listen((result) {
      if (result == ConnectivityResult.none) {
        emit(ConnectivityState.disconnected);
      } else {
        emit(ConnectivityState.connected);
      }
    });
  }

  checkConnectivity() async {
    final result = await _connectivity.checkConnectivity();
    if (result == ConnectivityResult.none) {
      emit(ConnectivityState.disconnected);
    } else {
      emit(ConnectivityState.connected);
    }
  }

  @override
  Future<void> close() {
    _subscription?.cancel();
    return super.close();
  }
}

问题原因

  1. 重复创建MaterialApp:外层已经存在一个MaterialApp作为BlocProvider的子组件,而BlocConsumer的builder中又返回了新的MaterialApp。每次网络状态变化时,新的MaterialApp会重新初始化应用核心配置(主题、路由、本地化等),这个过程会引发短暂黑屏。
  2. StatelessWidget状态不可靠:MyApp是StatelessWidget,其中的_isDialogDisplayed变量会在widget重建时被重置,可能导致弹窗逻辑混乱(比如重复弹窗、无法正确关闭)。

解决方案(修改后的代码)

main.dart

void main() {
  runApp(BlocProvider(
    create: (BuildContext context) => ConnectivityCubit()..checkConnectivity(),
    lazy: false,
    child: const MaterialApp(home: MyApp()),
  ));
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isDialogDisplayed = false;

  @override
  Widget build(BuildContext context) {
    return BlocConsumer<ConnectivityCubit, ConnectivityState>(
      listener: (context, state) {
        // 避免重复弹窗
        if (state == ConnectivityState.disconnected && !_isDialogDisplayed) {
          setState(() => _isDialogDisplayed = true);
          showDialog(
            context: context,
            barrierDismissible: false, // 可选:禁止点击空白关闭弹窗
            builder: (context) => const AlertDialog(
              title: Text('无网络连接'),
              content: Text('请检查你的网络连接状态。'),
            ),
          ).then((_) {
            // 弹窗关闭时重置状态
            setState(() => _isDialogDisplayed = false);
          });
        }
        // 网络恢复时关闭弹窗
        if (state == ConnectivityState.connected && _isDialogDisplayed) {
          if (Navigator.canPop(context)) {
            Navigator.of(context).pop();
          }
        }
      },
      builder: (context, state) {
        if (state == ConnectivityState.init) {
          return const Scaffold(
            body: Center(child: CircularProgressIndicator()),
          );
        }

        return Scaffold(
          body: state == ConnectivityState.connected
              ? const Center(child: Text('Hello World'))
              : const Center(child: CircularProgressIndicator()),
        );
      },
    );
  }
}

修改说明

  • 将MyApp改为StatefulWidget,确保_isDialogDisplayed状态在widget重建时不会丢失。
  • 移除BlocConsumer内部的MaterialApp,只保留外层唯一的MaterialApp,避免重复初始化导致黑屏。
  • 优化弹窗逻辑:添加状态判断防止重复弹窗,通过then方法在弹窗关闭时重置状态,增加Navigator.canPop避免无弹窗时调用pop报错。

内容的提问来源于stack exchange,提问作者Master Techie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 19:31:13