flutterdartstreamflutter-blocinternet-connection

Recheck internet connection in flutter only when retry button is clicked


Requirements:

Needs suggestion in:

Approach:

Why ?

main

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp();

  var isDialogDisplayed = false;
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    theme: CustomTheme.customTheme(),
    home: MultiBlocProvider(
        providers: Providers.getProviders,
        child: BlocConsumer<ConnectivityCubit, ConnectivityState>(
            listener: (context, state) {
          });
          if (state == ConnectivityState.disconnected) {
            isDialogDisplayed = true;
          }
          if (state == ConnectivityState.connected &&
              isDialogDisplayed == true) {
            isDialogDisplayed = false;
          }
        }, builder: (context, state) {
          if (state == ConnectivityState.init) {
            return const Scaffold(body: ShimmerHome()); 
          }
          return isDialogDisplayed
              ? Scaffold(
                  body: NoDataHelper(
                        ...
                        onTap: () {
                        if (state == ConnectivityState.connected) {
                          // isDialogDisplayed = false;          // Doesn't work
                        }
                      }),
                )
              : state == ConnectivityState.connected
                  ? MaterialApp.router(
                     ...
                    )
                  : const Scaffold(body: Center(child: ShimmerHome()));
        })),
  ));
}

Cubit

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) {
      checkConnectivity(result);
    });
  }

  checkConnectivity(ConnectivityResult result) async {
    if (result == ConnectivityResult.none) {
      emit(ConnectivityState.disconnected);
    } else {
      bool isInternetAvailable = await checkInternetConnectivity();
      if (isInternetAvailable) {
        emit(ConnectivityState.connected);
      } else {
        emit(ConnectivityState.disconnected);
      }
    }
  }

  Future<bool> checkInternetConnectivity() async {
    try {
      final response = await http
          .get(Uri.parse("https://www.google.com"))
          .timeout(Duration(seconds: 10)); // Set a 10-second timeout
      if (response.statusCode == 200) {
        return true;
      } else {
        return false;
      }
    } catch (e) {
      return false;
    }
  }

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

What am I looking for ?


Solution

  • I have made a few changes to your logic.

    1. You should only emit state when network is disconnected in case of network change listener subscription.
    2. No need to use BlocListener, you can directly make AlertDialog as body of Scaffold.

    Here is the code I came up with

    import 'dart:async';
    
    import 'package:connectivity_plus/connectivity_plus.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:http/http.dart' as http;
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      runApp(
        MultiBlocProvider(
          providers: [BlocProvider(create: (_) => ConnectivityCubit())],
          child: BlocBuilder<ConnectivityCubit, ConnectivityState>(
            builder: (context, state) {
              if (state == ConnectivityState.init) {
                return const MaterialApp(home: Scaffold(body: SizedBox.shrink()));
              } else if (state == ConnectivityState.disconnected) {
                return MaterialApp(
                  home: Scaffold(
                    appBar: AppBar(
                      title: const Text('Connectivity Check'),
                    ),
                    body: AlertDialog(
                      actions: [
                        ElevatedButton(
                          onPressed: () {
                            context.read<ConnectivityCubit>().checkConnectivity();
                          },
                          child: const Text('Retry'),
                        ),
                      ],
                      title: const Text('Internet not available'),
                    ),
                  ),
                );
              } else if (state == ConnectivityState.connected) {
                // repalce this with MaterialApp.router
                return MaterialApp(
                  home: Scaffold(
                    appBar: AppBar(
                      title: const Text('Connectivity Check'),
                    ),
                    body: const Center(child: Text('Connected')),
                  ),
                );
              } else {
                assert(false, "state not mapped");
                return const SizedBox.shrink();
              }
            },
          ),
        ),
      );
    }
    
    enum ConnectivityState {
      init,
      disconnected,
      connected,
    }
    
    class ConnectivityCubit extends Cubit<ConnectivityState> {
      final Connectivity _connectivity = Connectivity();
      StreamSubscription<ConnectivityResult>? _subscription;
      ConnectivityCubit() : super(ConnectivityState.init) {
        checkConnectivity();
        _subscription = _connectivity.onConnectivityChanged.listen((result) {
          if (result == ConnectivityResult.none) {
            emit(ConnectivityState.disconnected);
          }
        });
      }
    
      checkConnectivity() async {
        final result = await _connectivity.checkConnectivity();
        if (result == ConnectivityResult.none) {
          emit(ConnectivityState.disconnected);
        } else {
          bool isInternetAvailable = await checkInternetConnectivity();
          if (isInternetAvailable) {
            emit(ConnectivityState.connected);
          } else {
            emit(ConnectivityState.disconnected);
          }
        }
      }
    
      Future<bool> checkInternetConnectivity() async {
        try {
          final response = await http
              .get(Uri.parse("https://www.google.com"))
              .timeout(const Duration(seconds: 10)); // Set a 10-second timeout
          return response.statusCode == 200;
        } catch (e) {
          return false;
        }
      }
    
      @override
      Future<void> close() {
        _subscription?.cancel();
        return super.close();
      }
    }