skip to Main Content

I want to check for internet connection at every screen on my app just like Telegram does and whenever user goes offline, show an Offline banner on the top of the screen.

I have tried using connectivity_plus and internet_connection_checker plugins to check for this but the problem is I have to subscribe to a stream for this and if the device goes offline once then there is no way to subscribe to it again without clicking a button.

getConnectivity() =>
    subscription = Connectivity().onConnectivityChanged.listen(
      (ConnectivityResult result) async {
        isDeviceConnected = await InternetConnectionChecker().hasConnection;
        if (!isDeviceConnected && isAlertSet == false) {
          setState(() {
            constants.offline = true;
            print('Constants().offline ${constants.offline}');
            isAlertSet = true;
          });
        }
        print('off');
      },
    );

I’m using this code right now to check this issue but I don’t want to replicate this code on each and every screen and even if I do replicate it then there will be a lot of subscriptions that I’ll be subscribing to, which will mean that all the subscriptions will be disposed at the same time causing all sorts of issues.

4

Answers


  1. I myself use connectivity_plus and I have never found the problem you mentioned (if the device goes offline once then there is no way to subscribe to it again without clicking a button), you can use my example.
    If the user’s internet is disconnected, a modal will appear. If the user is connected again, the modal will be deleted automatically.
    Anyway, I put the option to check the internet again in the modal

    class CheckConnectionStream extends GetxController {
     bool isModalEnable = false;
     final loadingCheckConnectivity = false.obs;
    
     ConnectivityResult _connectionStatus = ConnectivityResult.none;
     final Connectivity _connectivity = Connectivity();
     late StreamSubscription<ConnectivityResult> _connectivitySubscription;
    
     Future<void> initConnectivity() async {
      late ConnectivityResult result;
     try {
        result = await _connectivity.checkConnectivity();
    
        loadingCheckConnectivity.value = false;
      } on PlatformException {
        return;
      }
    
      return _updateConnectionStatus(result);
     }
    
    Future<void> _updateConnectionStatus(ConnectivityResult result) async {
       _connectionStatus = result;
    
    if (result == ConnectivityResult.none) {
      if (isModalEnable != true) {
        isModalEnable = true;
        showDialogIfNotConnect();
      }
      } else {
      if (isModalEnable) {
        Get.back();
      }
      isModalEnable = false;
    }
    }
    
     showDialogIfNotConnect() {
        Get.defaultDialog(
          barrierDismissible: false,
          title: "check your network".tr,
           onWillPop: () async {
             return false;
           },
           middleText: "Your device is not currently connected to the Internet".tr,
          titleStyle: TextStyle(
          color: Get.isDarkMode ? Colors.white : Colors.black,
          ),
          middleTextStyle: TextStyle(
          color: Get.isDarkMode ? Colors.white : Colors.black,
          ),
        radius: 30,
        actions: [
          Obx(() => loadingCheckConnectivity.value
              ? const CustomLoading(
                  height: 30.0,
                  radius: 30.0,
                )
              : ElevatedButton(
                  onPressed: () async {
                    loadingCheckConnectivity.value = true;
                    EasyDebounce.debounce(
                        'check connectivity',
                       
                        const Duration(milliseconds: 1000), () async {
                      await initConnectivity();
                    });
                  },
                  child: Text(
                    'try again'.tr,
                    style: const TextStyle(color: Colors.white),
                  ),
                ))
        ]);
    }
    
    @override
    void onInit() {
     super.onInit();
      initConnectivity();
    
      _connectivitySubscription =
        _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
     }
    
    @override
     void onClose() {
     _connectivitySubscription.cancel();
     super.onClose();
     }
    }
    
    Login or Signup to reply.
  2. If you have custom Scaffold, then you have to edit it. Otherwise, create a new one and change all Scaffolds to your custom one. This allows you to easily apply changes that should be on all pages.

    Then, in the CustomScaffold create a Stack that contains page content and ValueListenableBuilder that listens to connection changes and if there is no internet displays error banner.

    class CustomScaffold extends StatefulWidget {
      const CustomScaffold({Key? key}) : super(key: key);
    
      @override
      State<CustomScaffold> createState() => _CustomScaffoldState();
    }
    
    class _CustomScaffoldState extends State<CustomScaffold> with WidgetsBindingObserver {
      StreamSubscription? connectivitySubscription;
      ValueNotifier<bool> isNetworkDisabled = ValueNotifier(false);
    
      void _checkCurrentNetworkState() {
        Connectivity().checkConnectivity().then((connectivityResult) {
          isNetworkDisabled.value = connectivityResult == ConnectivityResult.none;
        });
      }
    
      initStateFunc() {
        _checkCurrentNetworkState();
    
        connectivitySubscription = Connectivity().onConnectivityChanged.listen(
              (ConnectivityResult result) {
            isNetworkDisabled.value = result == ConnectivityResult.none;
          },
        );
      }
    
      @override
      void initState() {
        WidgetsBinding.instance.addObserver(this);
        initStateFunc();
        super.initState();
      }
    
      @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        super.didChangeAppLifecycleState(state);
    
        if (state == AppLifecycleState.resumed) {
          _checkCurrentNetworkState();
        }
      }
    
      @override
      void dispose() {
        WidgetsBinding.instance.removeObserver(this);
        connectivitySubscription?.cancel();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          fit: StackFit.expand,
          children: [
            Scaffold(
            ...
            ),
            ValueListenableBuilder(
              valueListenable: isNetworkDisabled,
              builder: (_, bool networkDisabled, __) =>
                  Visibility(
                    visible: networkDisabled,
                    child: YourErrorBanner(),
                  ),
            ),
          ],
        );
      }
    }
    
    Login or Signup to reply.
    1. First I created an abstract class called BaseScreenWidget
    2. used bloc state management to listen each time the internet connection changed then show toast or show upper banner with Blocbuilder
    abstract class BaseScreenWidget extends StatelessWidget {
      const BaseScreenWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            baseBuild(context),
            BlocConsumer<InternetConnectionBloc, InternetConnectionState>(
              listener: (context, state) {
                // if (!state.isConnected) {
                //   showToast("No Internet Connection");
                // }
              },
              builder: (context, state) {
                if (!state.isConnected) {
                  return const NoInternetWidget();
                }
                return const SizedBox.shrink();
              },
            ),
          ],
        );
      }
    
      Widget baseBuild(BuildContext context);
    }
    
    
    1. Made each screen only screen widgets contains Scaffold to extends BaseScreenWidget
    class MainScreen extends BaseScreenWidget {
      const MainScreen({super.key});
    
      @override
      Widget baseBuild(BuildContext context) {
         return const Scaffold(
          body: MainScreenBody(),
        );
      }
    }
    
    • it’s very helpful to wrap the Column with SafeArea in the build method in BaseScreen.
    Login or Signup to reply.
  3. USE THIS SIMPLE TECHNIQUE only need this package: Internet Connection Checker. If you turn off your network it will tell you

    connection_checker.dart

    import 'dart:async';
    import 'package:flutter/material.dart';
    
    import 'package:internet_connection_checker/internet_connection_checker.dart';
    
    final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
    
    class CheckMyConnection {
      static bool isConnect = false;
      static bool isInit = false;
    
      static hasConnection(
          {required void Function() hasConnection,
          required void Function() noConnection}) async {
        Timer.periodic(const Duration(seconds: 1), (_) async {
          isConnect = await InternetConnectionChecker().hasConnection;
          if (isInit == false && isConnect == true) {
            isInit = true;
            hasConnection.call();
          } else if (isInit == true && isConnect == false) {
            isInit = false;
            noConnection.call();
          }
        });
      }
    }
    

    base.dart

    import 'package:flutter/material.dart';
    import 'connection_checker.dart';
    
    class Base extends StatefulWidget {
      final String title;
      const Base({Key? key, required this.title}) : super(key: key);
    
      @override
      State<Base> createState() => _BaseState();
    }
    
    class _BaseState extends State<Base> {
      final snackBar1 = SnackBar(
        content: const Text(
          'Internet Connected',
          style: TextStyle(color: Colors.white),
        ),
        backgroundColor: Colors.green,
      );
    
      final snackBar2 = SnackBar(
        content: const Text(
          'No Internet Connection',
          style: TextStyle(color: Colors.white),
        ),
        backgroundColor: Colors.red,
      );
    
      @override
      void initState() {
        super.initState();
        CheckMyConnection.hasConnection(hasConnection: () {
          ScaffoldMessenger.of(navigatorKey.currentContext!)
              .showSnackBar(snackBar1);
        }, noConnection: () {
          ScaffoldMessenger.of(navigatorKey.currentContext!)
              .showSnackBar(snackBar2);
        });
      }
    
      @override
      Widget build(BuildContext context) {
      return DefaultTabController(
            length: 3,
            child: Scaffold(
              key: navigatorKey,
              appBar: AppBar(
                bottom: const TabBar(
                  tabs: [
                    Tab(icon: Icon(Icons.directions_car)),
                    Tab(icon: Icon(Icons.directions_transit)),
                    Tab(icon: Icon(Icons.directions_bike)),
                  ],
                ),
                title: const Text('Tabs Demo'),
              ),
              body: const TabBarView(
                children: [
                  Icon(Icons.directions_car),
                  Icon(Icons.directions_transit),
                  Icon(Icons.directions_bike),
                ],
              ),
            ),
          );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search