Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Error’d: Pickup Sticklers

      September 27, 2025

      From Prompt To Partner: Designing Your Custom AI Assistant

      September 27, 2025

      Microsoft unveils reimagined Marketplace for cloud solutions, AI apps, and more

      September 27, 2025

      Design Dialects: Breaking the Rules, Not the System

      September 27, 2025

      Building personal apps with open source and AI

      September 12, 2025

      What Can We Actually Do With corner-shape?

      September 12, 2025

      Craft, Clarity, and Care: The Story and Work of Mengchu Yao

      September 12, 2025

      Cailabs secures €57M to accelerate growth and industrial scale-up

      September 12, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

      September 28, 2025
      Recent

      Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

      September 28, 2025

      Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

      September 28, 2025

      The first browser with JavaScript landed 30 years ago

      September 27, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured
      Recent
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»How to Build an Always Listening Network Connectivity Checker in Flutter using BLoC

    How to Build an Always Listening Network Connectivity Checker in Flutter using BLoC

    August 18, 2025

    Many mobile applications require a stable internet connection to provide a smooth user experience. And as a Flutter developer, you need a robust way to handle network state changes, ensuring that your app responds gracefully whether it’s connected, disconnected, or transitioning between states.

    This article will give you a detailed walkthrough of building a comprehensive network connectivity checker using a powerful combination of modern Flutter packages and architectural patterns.

    We will leverage:

    1. connectivity_plus: A package to check for basic network connectivity (for example, WiFi, mobile data, Ethernet).

    2. internet_connection_checker: A more reliable tool that goes beyond a simple network check by actively pinging a known URL to confirm actual internet access.

    3. A direct HTTP call to a trusted URL (like Google): As a failsafe, a direct network call can serve as a final confirmation of connectivity.

    4. rxdart with debounce: To prevent excessive and rapid network checks, which can be inefficient and drain the device’s battery.

    5. Dependency Injection with get_it and injectable: For a clean, modular, and testable codebase.

    6. State Management with BLoC and freezed: The BLoC pattern separates business logic from the UI, and freezed simplifies the creation of immutable states and events.

    7. Streams: To enable a reactive, “always-listening” approach to network status changes.

    8. fluttertoast: To provide clear, non-intrusive user feedback.

    Let’s dive in.

    Table of Contents:

    1. Prerequisites

    2. Step 1: Set Up Dependency Injection with get_it and injectable

    3. Step 2: Implement the Network Connectivity Checker

    4. Step 3: Create the BLoC for Network Connectivity

    5. Step 4: Integrate the BLoC with the UI

    6. Step 5: Display Toast Notifications

    7. Conclusion

    8. References

    Prerequisites

    Before you begin, make sure you have a basic understanding of:

    1. Flutter and Dart: The fundamentals of building apps with Flutter.

    2. Asynchronous Programming: Concepts like async, await, and Future.

    3. BLoC pattern: The core principles of BLoC (Business Logic Component) for state management.

    4. Code generation: How to use packages like build_runner to generate boilerplate code.

    Step 1: Set Up Dependency Injection with get_it and injectable

    Dependency Injection (DI) is a software design pattern that allows a class to receive its dependencies from an external source rather than creating them itself. This makes your code more flexible, reusable, and easier to test.

    Let’s look at the two tools we’ll use to implement this:

    1. get_it is a “service locator” that acts as a central registry. You register your services (dependencies) with get_it, and it provides a way to retrieve their single instance from anywhere in your app. It’s a simple and effective alternative to more complex DI frameworks.

    2. injectable is a code-generation package that works with get_it. By annotating your classes with @injectable, @lazySingleton, or @module, injectable automatically writes the boilerplate code to register your dependencies with get_it for you, saving you from manual setup.

    First, create a new Flutter project like this:

    flutter create my_injectable_project
    <span class="hljs-built_in">cd</span> my_injectable_project
    

    Next, add the necessary packages to your pubspec.yaml file:

    <span class="hljs-attr">dependencies:</span>
      <span class="hljs-attr">freezed_annotation:</span> <span class="hljs-string">^2.4.1</span>
      <span class="hljs-attr">rxdart:</span> <span class="hljs-string">^0.28.0</span>
      <span class="hljs-attr">get_it:</span> <span class="hljs-string">^7.6.7</span>
      <span class="hljs-attr">injectable:</span> <span class="hljs-string">^2.3.2</span>
      <span class="hljs-attr">internet_connection_checker:</span> <span class="hljs-string">^1.0.0+1</span>
      <span class="hljs-attr">connectivity_plus:</span> <span class="hljs-string">^5.0.2</span>
      <span class="hljs-attr">fluttertoast:</span> <span class="hljs-string">^8.2.4</span>
      <span class="hljs-attr">flutter_bloc:</span> <span class="hljs-string">^8.1.3</span>
      <span class="hljs-attr">http:</span> <span class="hljs-string">^0.13.3</span>
    
    <span class="hljs-attr">dev_dependencies:</span>
      <span class="hljs-attr">build_runner:</span>
      <span class="hljs-attr">freezed:</span> <span class="hljs-string">^2.4.7</span>
      <span class="hljs-attr">injectable_generator:</span> <span class="hljs-string">^2.4.1</span>
    

    So what’s going on here?

    • freezed_annotation & freezed: Used for creating immutable data classes for BLoC states and events.

    • rxdart: Provides powerful stream-related operators, including debounceTime, which is essential for our connectivity checker.

    • get_it & injectable: For dependency injection.

    • internet_connection_checker & connectivity_plus: The core packages for checking network status.

    • fluttertoast: To display user notifications.

    • flutter_bloc: The main BLoC package.

    • http: A package to make HTTP requests, used for the Google URL check.

    • build_runner: The command-line tool that runs the code generators.

    • injectable_generator: The generator that works with injectable.

    Now it’s time to create the injection configuration file. Go ahead and create a file, for example, lib/core/dependency_injection/injection.dart, to set up get_it and injectable.

    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:get_it/get_it.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:injectable/injectable.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:my_injectable_project/core/dependency_injection/injection.config.dart'</span>;
    
    <span class="hljs-comment">// The global instance of GetIt</span>
    <span class="hljs-keyword">final</span> GetIt getIt = GetIt.instance;
    
    <span class="hljs-comment">// The annotation @injectableInit tells injectable to generate the init method</span>
    <span class="hljs-meta">@injectableInit</span>
    <span class="hljs-keyword">void</span> configureDependencies(<span class="hljs-built_in">String</span> env) => getIt.init(environment: env);
    
    • final GetIt getIt = GetIt.instance;: We create a static instance of GetIt that can be accessed globally.

    • @injectableInit: This annotation signals to injectable_generator that this is the file where it should generate the dependency registration code.

    • void configureDependencies(String env) => getIt.init(environment: env);: This function initializes get_it and allows us to configure it for different environments (e.g., ‘dev’, ‘prod’).

    Lastly, we need to create a module for dependencies. Create a module file, for example, lib/core/dependency_injection/register_module.dart, to register third-party classes that don’t belong to your own project structure.

    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:connectivity_plus/connectivity_plus.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:get_it/get_it.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:injectable/injectable.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:internet_connection_checker/internet_connection_checker.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:my_injectable_project/core/network_info/network_info.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:my_injectable_project/features/network_info/bloc/network_info_bloc.dart'</span>;
    
    <span class="hljs-comment">// The @module annotation marks this class as a module for injectable</span>
    <span class="hljs-meta">@module</span>
    <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterModule</span> </span>{
    
      <span class="hljs-comment">// A @lazySingleton means the instance will be created only when it's first requested</span>
      <span class="hljs-meta">@lazySingleton</span>
      Connectivity <span class="hljs-keyword">get</span> connectivity => Connectivity();
    
      <span class="hljs-meta">@lazySingleton</span>
      InternetConnectionChecker <span class="hljs-keyword">get</span> internetConnectionChecker => InternetConnectionChecker();
    
      <span class="hljs-meta">@lazySingleton</span>
      NetworkInfoImpl <span class="hljs-keyword">get</span> networkInfo => NetworkInfoImpl(
            connectivity: connectivity,
            internetConnectionChecker: internetConnectionChecker,
          );
    
      <span class="hljs-meta">@lazySingleton</span>
      NetworkInfoBloc <span class="hljs-keyword">get</span> networkInfoBloc => NetworkInfoBloc(
            networkInfo: getIt<NetworkInfo>(),
            connectivity: getIt<Connectivity>(),
          );
    }
    
    • @module: A special annotation that marks a class as a module for injectable. Modules are useful for registering third-party classes or creating instances of classes that require complex setup.

    • @lazySingleton: This annotation tells injectable to create a single instance of the class and reuse it every time it is requested. The “lazy” part means the instance is not created until it’s needed for the first time.

    Step 2: Implement the Network Connectivity Checker

    Interface and Implementation

    It’s good practice to program against an interface rather than a concrete implementation. This allows for easy swapping of implementations and makes testing simpler. Below, lib/core/network_info/network_info.dart is the abstract class while lib/core/network_info/network_info_impl.dart is the implementation. This is where the functionality of the flow lies, which the bloc uses.

    lib/core/network_info/network_info.dart:

    <span class="hljs-comment">// The abstract class defines the contract for our network checker</span>
    <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkInfo</span> </span>{
      Future<<span class="hljs-built_in">bool</span>> <span class="hljs-keyword">get</span> isConnected;
    }
    

    lib/core/network_info/network_info_impl.dart:

    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:connectivity_plus/connectivity_plus.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/foundation.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:http/http.dart'</span> <span class="hljs-keyword">as</span> http;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:injectable/injectable.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:internet_connection_checker/internet_connection_checker.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:my_injectable_project/core/network_info/network_info.dart'</span>;
    
    <span class="hljs-comment">// @LazySingleton(as: NetworkInfo) tells injectable to register this class</span>
    <span class="hljs-comment">// as a lazy singleton, and to provide it when a NetworkInfo is requested.</span>
    <span class="hljs-meta">@LazySingleton</span>(<span class="hljs-keyword">as</span>: NetworkInfo)
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkInfoImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">NetworkInfo</span> </span>{
      <span class="hljs-keyword">final</span> Connectivity connectivity;
      <span class="hljs-keyword">final</span> InternetConnectionChecker internetConnectionChecker;
    
      <span class="hljs-keyword">const</span> NetworkInfoImpl({
        <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.connectivity,
        <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.internetConnectionChecker,
      });
    
      <span class="hljs-meta">@override</span>
      Future<<span class="hljs-built_in">bool</span>> <span class="hljs-keyword">get</span> isConnected <span class="hljs-keyword">async</span> {
        <span class="hljs-keyword">try</span> {
          <span class="hljs-built_in">bool</span> isDeviceConnected = <span class="hljs-keyword">false</span>;
          <span class="hljs-comment">// First, check the connectivity type (WiFi, mobile, etc.)</span>
          <span class="hljs-keyword">final</span> connectivityResult = <span class="hljs-keyword">await</span> connectivity.checkConnectivity();
          debugPrint(<span class="hljs-string">'Connectivity Result: <span class="hljs-subst">$connectivityResult</span>'</span>);
    
          <span class="hljs-keyword">if</span> (connectivityResult != ConnectivityResult.none) {
            <span class="hljs-comment">// If there's a network type, verify actual internet access</span>
            isDeviceConnected = <span class="hljs-keyword">await</span> internetConnectionChecker.hasConnection ||
                <span class="hljs-keyword">await</span> hasInternetConnection();
          }
          debugPrint(<span class="hljs-string">'Device Connected: <span class="hljs-subst">$isDeviceConnected</span>'</span>);
          <span class="hljs-keyword">return</span> isDeviceConnected;
        } <span class="hljs-keyword">catch</span> (e) {
          debugPrint(<span class="hljs-string">'Error checking network connection: <span class="hljs-subst">$e</span>'</span>);
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
        }
      }
    
      <span class="hljs-comment">// A redundant but useful check with a direct HTTP call</span>
      Future<<span class="hljs-built_in">bool</span>> hasInternetConnection() <span class="hljs-keyword">async</span> {
        <span class="hljs-keyword">try</span> {
          <span class="hljs-keyword">final</span> response = <span class="hljs-keyword">await</span> http.<span class="hljs-keyword">get</span>(<span class="hljs-built_in">Uri</span>.parse(<span class="hljs-string">'https://www.google.com'</span>)).timeout(
            <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">5</span>),
          );
          <span class="hljs-keyword">if</span> (response.statusCode == <span class="hljs-number">200</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
          }
        } <span class="hljs-keyword">catch</span> (e) {
          debugPrint(<span class="hljs-string">'Error checking internet connection: <span class="hljs-subst">$e</span>'</span>);
        }
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
      }
    }
    
    • @LazySingleton(as: NetworkInfo): This is the key annotation. It registers NetworkInfoImpl as a singleton that implements the NetworkInfo interface. When getIt<NetworkInfo>() is called, an instance of NetworkInfoImpl will be provided.

    • connectivity.checkConnectivity(): Provides a quick check of the device’s connection type.

    • internetConnectionChecker.hasConnection: This package is more reliable than just checking the network type, as a device can be “connected” to a WiFi network without having internet access. internet_connection_checker actively pings a series of addresses to verify.

    • hasInternetConnection(): A fallback function that makes a direct HTTP request to a reliable URL like Google. This provides an extra layer of verification.

    Step 3: Create the BLoC for Network Connectivity

    The BLoC handles the business logic of checking the network status and emitting the appropriate state changes to the UI.

    lib/features/network_info/bloc/network_info_bloc.dart:

    <span class="hljs-keyword">import</span> <span class="hljs-string">'dart:async'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:bloc/bloc.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:connectivity_plus/connectivity_plus.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/foundation.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:injectable/injectable.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:my_injectable_project/core/network_info/network_info.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:rxdart/rxdart.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:freezed_annotation/freezed_annotation.dart'</span>;
    
    <span class="hljs-keyword">part</span> <span class="hljs-string">'network_info_bloc.freezed.dart'</span>;
    <span class="hljs-keyword">part</span> <span class="hljs-string">'network_info_event.dart'</span>;
    <span class="hljs-keyword">part</span> <span class="hljs-string">'network_info_state.dart'</span>;
    
    <span class="hljs-comment">// @injectable marks this class to be registered by injectable</span>
    <span class="hljs-meta">@injectable</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkInfoBloc</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Bloc</span><<span class="hljs-title">NetworkInfoEvent</span>, <span class="hljs-title">NetworkInfoState</span>> </span>{
      <span class="hljs-keyword">final</span> NetworkInfo networkInfo;
      <span class="hljs-keyword">final</span> Connectivity connectivity;
      <span class="hljs-keyword">late</span> StreamSubscription<<span class="hljs-built_in">List</span><ConnectivityResult>> connectivitySubscription;
    
      NetworkInfoBloc({
        <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.networkInfo,
        <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.connectivity,
      }) : <span class="hljs-keyword">super</span>(NetworkInfoState.initial()) {
        <span class="hljs-comment">// Custom event transformer for debouncing</span>
        EventTransformer<T> debounce<T>(<span class="hljs-built_in">Duration</span> duration) {
          <span class="hljs-keyword">return</span> (events, mapper) => events.debounceTime(duration).flatMap(mapper);
        }
    
        <span class="hljs-comment">// The 'on' method maps events to states</span>
        <span class="hljs-keyword">on</span><CheckNetwork>(
          _onCheckNetwork,
          <span class="hljs-comment">// Apply the debounce transformer to limit the rate of function calls</span>
          transformer: debounce(
            <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
          ),
        );
    
        <span class="hljs-comment">// Listen to changes from the connectivity_plus package</span>
        connectivitySubscription = connectivity.onConnectivityChanged.listen((connectivityResult) <span class="hljs-keyword">async</span> {
          <span class="hljs-keyword">await</span> Future.delayed(<span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>)); <span class="hljs-comment">// Small delay to avoid race conditions</span>
          debugPrint(<span class="hljs-string">'Connectivity Result after delay: <span class="hljs-subst">$connectivityResult</span>'</span>);
          add(<span class="hljs-keyword">const</span> CheckNetwork());
        });
      }
    
      <span class="hljs-comment">// The event handler for CheckNetwork</span>
      Future<<span class="hljs-keyword">void</span>> _onCheckNetwork(
        CheckNetwork event,
        Emitter<NetworkInfoState> emit,
      ) <span class="hljs-keyword">async</span> {
        <span class="hljs-keyword">final</span> isConnected = <span class="hljs-keyword">await</span> networkInfo.isConnected;
        <span class="hljs-comment">// Only emit a new state if the network status has actually changed</span>
        <span class="hljs-keyword">if</span> (state.networkStatus != isConnected) {
          emit(state.copyWith(networkStatus: isConnected));
        }
        debugPrint(
            <span class="hljs-string">'Network Status ==> <span class="hljs-subst">${isConnected ? <span class="hljs-string">"Data connection is available."</span> : <span class="hljs-string">"You are disconnected from the internet."</span>}</span>'</span>);
      }
    
      <span class="hljs-meta">@override</span>
      Future<<span class="hljs-keyword">void</span>> close() {
        <span class="hljs-comment">// It's crucial to cancel the stream subscription to prevent memory leaks</span>
        connectivitySubscription.cancel();
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.close();
      }
    }
    
    • EventTransformer<T> debounce<T>(Duration duration): This is a custom transformer. It uses rxdart‘s debounceTime operator to wait for a specified duration of inactivity before allowing the event to be processed. This is perfect for preventing a cascade of network checks.

    • connectivity.onConnectivityChanged.listen(...): This creates a subscription to a stream of ConnectivityResult. Whenever the device’s connectivity status changes (for example, switches from WiFi to mobile data), this stream emits a new value, which in turn triggers our CheckNetwork event.

    • _onCheckNetwork(...): This function is the heart of the BLoC’s logic. It calls networkInfo.isConnected to get the current status and then emits a new state if the status has changed.

    • close(): Overriding this method is vital for proper resource management. It’s where we clean up our StreamSubscription to avoid memory leaks.

    Events and States

    freezed is a code-generation tool that makes it easy to create immutable data classes, which are essential for the BLoC pattern.

    lib/features/network_info/bloc/network_info_event.dart:

    <span class="hljs-keyword">part</span> of <span class="hljs-string">'network_info_bloc.dart'</span>;
    
    <span class="hljs-meta">@freezed</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkInfoEvent</span> <span class="hljs-title">with</span> <span class="hljs-title">_</span>$<span class="hljs-title">NetworkInfoEvent</span> </span>{
      <span class="hljs-keyword">const</span> <span class="hljs-keyword">factory</span> NetworkInfoEvent.checkNetwork() = CheckNetwork;
    }
    
    • @freezed: This annotation triggers freezed to generate the boilerplate code for this class.

    • const factory NetworkInfoEvent.checkNetwork() = CheckNetwork;: This defines a single event for our BLoC, which is CheckNetwork.

    lib/features/network_info/bloc/network_info_state.dart:

    <span class="hljs-keyword">part</span> of <span class="hljs-string">'network_info_bloc.dart'</span>;
    
    <span class="hljs-meta">@freezed</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkInfoState</span> <span class="hljs-title">with</span> <span class="hljs-title">_</span>$<span class="hljs-title">NetworkInfoState</span> </span>{
      <span class="hljs-keyword">const</span> <span class="hljs-keyword">factory</span> NetworkInfoState({<span class="hljs-keyword">required</span> <span class="hljs-built_in">bool</span> networkStatus}) = _NetworkInfoState;
    
      <span class="hljs-keyword">factory</span> NetworkInfoState.initial() => <span class="hljs-keyword">const</span> NetworkInfoState(
        networkStatus: <span class="hljs-keyword">true</span>,
      );
    }
    
    • const factory NetworkInfoState(...): This defines our state, which simply holds a networkStatus boolean.

    • factory NetworkInfoState.initial(): A helper factory to create the initial state of the BLoC.

    Run the Code Generator

    To generate the *.freezed.dart and *.g.dart files, run the following command in your terminal:

    flutter pub run build_runner build --delete-conflicting-outputs
    

    This command will watch your project for changes and automatically regenerate the necessary files.

    Step 4: Integrate the BLoC with the UI

    Finally, we’ll connect our BLoC to the Flutter UI to react to state changes.

    In your main widget, for example, main.dart, you can access the BLoC through getIt.

    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_bloc/flutter_bloc.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:fluttertoast/fluttertoast.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:my_injectable_project/core/dependency_injection/injection.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:my_injectable_project/features/network_info/bloc/network_info_bloc.dart'</span>;
    
    <span class="hljs-keyword">void</span> main() {
      <span class="hljs-comment">// Initialize dependency injection</span>
      configureDependencies(<span class="hljs-string">'dev'</span>);
      runApp(<span class="hljs-keyword">const</span> MyApp());
    }
    
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
      <span class="hljs-keyword">const</span> MyApp({<span class="hljs-keyword">super</span>.key});
    
      <span class="hljs-meta">@override</span>
      Widget build(BuildContext context) {
        <span class="hljs-comment">// Provide the BLoC to the widget tree</span>
        <span class="hljs-keyword">return</span> BlocProvider(
          create: (context) => getIt<NetworkInfoBloc>(),
          child: MaterialApp(
            title: <span class="hljs-string">'Network Checker Demo'</span>,
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: <span class="hljs-keyword">const</span> NetworkCheckerPage(),
          ),
        );
      }
    }
    
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NetworkCheckerPage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
      <span class="hljs-keyword">const</span> NetworkCheckerPage({<span class="hljs-keyword">super</span>.key});
    
      <span class="hljs-meta">@override</span>
      State<NetworkCheckerPage> createState() => _NetworkCheckerPageState();
    }
    
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_NetworkCheckerPageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span><<span class="hljs-title">NetworkCheckerPage</span>> </span>{
      <span class="hljs-keyword">final</span> NetworkInfoBloc networkInfoBloc = getIt<NetworkInfoBloc>();
    
      <span class="hljs-meta">@override</span>
      <span class="hljs-keyword">void</span> initState() {
        <span class="hljs-keyword">super</span>.initState();
        <span class="hljs-comment">// Listen to the BLoC's state stream</span>
        networkInfoBloc.stream.listen((state) {
          <span class="hljs-keyword">if</span> (state.networkStatus) {
            toastInfo(
              msg: <span class="hljs-string">"Data connection is available."</span>,
              status: Status.success,
            );
          } <span class="hljs-keyword">else</span> {
            toastInfo(
              msg: <span class="hljs-string">"You are disconnected from the internet."</span>,
              status: Status.error,
            );
          }
        });
      }
    
      <span class="hljs-meta">@override</span>
      Widget build(BuildContext context) {
        <span class="hljs-keyword">return</span> Scaffold(
          appBar: AppBar(
            title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Network Connectivity'</span>),
          ),
          body: Center(
            child: BlocBuilder<NetworkInfoBloc, NetworkInfoState>(
              builder: (context, state) {
                <span class="hljs-keyword">return</span> Text(
                  state.networkStatus
                      ? <span class="hljs-string">'Connected to the Internet!'</span>
                      : <span class="hljs-string">'Disconnected from the Internet.'</span>,
                  style: TextStyle(
                    fontSize: <span class="hljs-number">20</span>,
                    color: state.networkStatus ? Colors.green : Colors.red,
                  ),
                );
              },
            ),
          ),
        );
      }
    }
    
    • BlocProvider: This widget provides the NetworkInfoBloc instance to the widget tree, making it accessible to any child widget via BlocProvider.of<NetworkInfoBloc>(context).

    • networkInfoBloc.stream.listen(...): In initState, we subscribe to the BLoC’s state stream. Each time a new state is emitted (which happens when the network status changes), our listener is triggered, and we can display a toast notification.

    • BlocBuilder: This widget is used to rebuild the UI in response to state changes. It listens for new states from the NetworkInfoBloc and rebuilds its builder function, updating the Text widget to reflect the current network status.

    Step 5: Display Toast Notifications

    The fluttertoast package provides a simple, platform-agnostic way to show non-intrusive messages.

    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
    <span class="hljs-keyword">import</span> <span class="hljs-string">'package:fluttertoast/fluttertoast.dart'</span>;
    
    <span class="hljs-keyword">enum</span> Status { success, error }
    
    <span class="hljs-keyword">void</span> toastInfo({
      <span class="hljs-keyword">required</span> <span class="hljs-built_in">String</span> msg,
      <span class="hljs-keyword">required</span> Status status,
    }) {
      Fluttertoast.showToast(
        msg: msg,
        toastLength: Toast.LENGTH_SHORT,
        gravity: ToastGravity.BOTTOM,
        backgroundColor: status == Status.success ? Colors.green : Colors.red,
        textColor: Colors.white,
        fontSize: <span class="hljs-number">16.0</span>,
      );
    }
    

    This helper function simplifies the process of showing toasts by allowing you to specify a message and a status, which determines the background color.

    Conclusion

    By combining the power of the BLoC pattern, dependency injection with get_it and injectable, and robust network-checking libraries, you can build a highly reliable and maintainable network connectivity checker in your Flutter application.

    This architecture ensures your app is responsive to network changes and provides a clean separation of concerns, making your codebase scalable and easy to test.

    References

    Here are some references that support the concepts and packages used in the article:

    Flutter and Dart Fundamentals:

    1. Flutter Official Documentation: Provides comprehensive guides on Flutter development, including widgets, state management, and asynchronous programming.

    2. Dart Official Documentation: Details Dart language features, including asynchronous programming with Future and Stream.

    Connectivity and Network Checking:

    1. connectivity_plus package on Pub.dev: Official documentation for the connectivity_plus plugin, explaining its usage for checking network connectivity types.

    2. internet_connection_checker package on Flutter Gems: Details the internet_connection_checker package, which verifies actual internet access by pinging external servers.

    3. http package on Pub.dev: The official documentation for making HTTP requests in Dart and Flutter.

    Dependency Injection:

    1. get_it package on Pub.dev: The official documentation for get_it, a simple service locator for Dart and Flutter.

    2. injectable package on Pub.dev: The official documentation for injectable, a code generator for get_it that simplifies dependency registration.

    3. State Management (BLoC): flutter_bloc package on Pub.dev – the official documentation for the flutter_bloc package, providing widgets and utilities for implementing the BLoC pattern.

    Immutability and Code Generation:

    1. freezed package on Pub.dev: The official documentation for freezed, a powerful code generator for creating immutable data classes.

    2. build_runner package on Pub.dev: The tool used to run code generators like injectable_generator and freezed.

    Reactive Programming (RxDart) and Streams:

    1. rxdart package on Pub.dev: Official documentation for RxDart, which extends Dart’s Stream API with powerful operators like debounceTime.

    2. “Stream class – dart:async library” on Flutter API Docs: The official Dart documentation for the Stream class.

    User Feedback:

    1. fluttertoast package on Pub.dev: Official documentation for the fluttertoast package for displaying toast messages.

    Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleHow to Deploy a Next.js API with PostgreSQL and Sevalla
    Next Article Create a travel planning agentic workflow with Amazon Nova

    Related Posts

    Development

    Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

    September 28, 2025
    Development

    Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

    September 28, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Streamline Mass Insertions with Laravel’s fillAndInsert() Method

    Development
    New TCESB Malware Found in Active Attacks Exploiting ESET Security Scanner

    New TCESB Malware Found in Active Attacks Exploiting ESET Security Scanner

    Development

    Symantec: Windows-lek voor uitkomen patch gebruikt bij malware-aanval

    Security

    5 Game-Changing Ways Generative AI Is Redefining Retail Experiences🛍️

    Web Development

    Highlights

    Development

    Life in Startup Pivot Hell with Ex-Microsoft Lonewolf Engineer Sam Crombie [Podcast #171]

    May 9, 2025

    On this week’s episode of the podcast, freeCodeCamp founder Quincy Larson interviews Sam Crombie. He’s…

    Will super-smart AI be attacking us anytime soon?

    April 22, 2025

    How to Dockerize Your Django Project

    April 18, 2025

    CISA Adds PaperCut NG/MF CSRF Vulnerability to KEV Catalog Amid Active Exploitation

    July 29, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.