How to make a listening network connectivity checker in the flurry using a block

by SkillAiNest

Many mobile applications require stable internet connection to provide smooth user experience. And as a developer of a flurry, you need a strong way to handle network state changes, making sure that your app will respond beautifully, whether it is connected, disconnected, or transferred between states.

This article will provide you with a detailed walkthrough for the construction of a comprehensive network connectivity checker using a powerful combination of modern flutter packages and architectural patterns.

We will take advantage of:

  1. connectivity_plus: A package to check the basic network contact (for example, Wi -Fi, mobile data, Ethernet).

  2. internet_connection_checker: A more reliable tool that confirms the Internet access to a leading URL actively ping a simple network check.

  3. HTTP call directly to a trusted URL (such as Google): As a Fail Safe, can directly serve as a final confirmation of network call contact.

  4. rxdart With debounce: To prevent excessive and high -speed network checks, which can be defective and remove the device’s battery.

  5. With a dependent injection get_it And injectable: Clean, modular and for the test code base.

  6. State management with block and freezed: Block patterns separate business logic from UI, and freezed Ease the creation of incredible states and events.

  7. Rivers: A reaction to the changes in a network status, enabling the “always listing” approach.

  8. fluttertoast: Clear, non -interference to provide user feedback.

Let’s sink.

Table of contents:

  1. Provisions

  2. Step 1: Set up a dependent injection with get_it and injection

  3. Step 2: Implement the Network Connectivity Checker

  4. Step 3: Create block for network connectivity

  5. Step 4: Connect the block with UI

  6. Step 5: Display toast notifications

  7. Conclusion

  8. References

Provisions

Before starting, make sure you have a basic understanding of it:

  1. Fluttering and dart: The basic principles of making apps with flurry.

  2. Unconstitutional programming: Ideas such as asyncFor, for, for,. awaitAnd Future.

  3. Block patterns: The basic principles of block (business logic component) for state management.

  4. Code generation: Use the package like build_runner To produce a boiler plate code.

Step 1: Sort with dependent injection get_it And injectable

Dependent Injection (DI) is a software design pattern that allows a class to get its own dependence from an external source, rather than making the class itself. This makes your code more flexible, reusable and easy to test.

Let’s take a look at the two tools we’ll use to implement it:

  1. get_it There is a “service locator” that acts as a central registry. You enroll with your services (dependent) get_itAnd this provides a way to recover the only example of them from anywhere in your app. This is an easy and effective alternative to more complex DI framework.

  2. injectable Is a code generation package that works get_it. By explaining with your classes @injectableFor, for, for,. @lazySingletonOr @moduleFor, for, for,. injectable Automatically writes boiler plate code to register his dependency get_it For you, protect you from manual setup.

First, make such a new fluttering project:

flutter create my_injectable_project
cd my_injectable_project

Next, add the required package to your pubspec.yaml File:

dependencies:
  freezed_annotation: ^2.4.1
  rxdart: ^0.28.0
  get_it: ^7.6.7
  injectable: ^2.3.2
  internet_connection_checker: ^1.0.0+1
  connectivity_plus: ^5.0.2
  fluttertoast: ^8.2.4
  flutter_bloc: ^8.1.3
  http: ^0.13.3

dev_dependencies:
  build_runner:
  freezed: ^2.4.7
  injectable_generator: ^2.4.1

So what’s going on here?

  • freezed_annotation & & & & & & & freezed: Block states and events are used to create an unintended data class.

  • rxdart: Stream -related powerful operators provides, including debounceTimeWhich is essential for our contact checker.

  • get_it & & & & & & & injectable: Depending for injection.

  • internet_connection_checker & & & & & & & connectivity_plus: Basic packages to check the status of the network.

  • fluttertoast: Displaying user notifications.

  • flutter_bloc: Central block package.

  • http: A package to make HTTP applications, which is used for Google URL check.

  • build_runner: Command line tool that runs code generators.

  • injectable_generator: A generator who works injectable.

The time has come to create an injection configuration file. Go ahead and make a file, for example, lib/core/dependency_injection/injection.dartTo sort, get_it And injectable.

import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'package:my_injectable_project/core/dependency_injection/injection.config.dart';


final GetIt getIt = GetIt.instance;


@injectableInit
void configureDependencies(String env) => getIt.init(environment: env);
  • final GetIt getIt = GetIt.instance;: We make a steady example GetIt It can be accessed globally.

  • @injectableInit: This interpretation is a signal injectable_generator That this is the file where it should produce a dependent registration code.

  • void configureDependencies(String env) => getIt.init(environment: env);: This function begins get_it And allows us to create it for a different environment (such as, ‘giant’, ‘product’).

Finally, we need to build a single module of dependence. Create a module file, for example, lib/core/dependency_injection/register_module.dartTo register third party classes that do not belong to your own project structure.

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:my_injectable_project/core/network_info/network_info.dart';
import 'package:my_injectable_project/features/network_info/bloc/network_info_bloc.dart';


@module
abstract class RegisterModule 
            await hasInternetConnection();
      
  • @module: A special interpretation that marks the class as a module injectable. The module is useful to register third -party classes or create an example of classes, which require complex setups.

  • @lazySingleton: This interpretation tells injectable Creating an example of the class and reusing it whenever it is requested. The section of the “lack” means that the example is not created unless it is needed for the first time.

Step 2: Implement the Network Connectivity Checker

Interface and implementation

Program against an interface rather than solid implementation is a good practice. This allows the implementation to be easily changed and makes the test easier. Down, down, lib/core/network_info/network_info.dart Summary is the class while lib/core/network_info/network_info_impl.dart Implementation. This is where the flow functionality lies, which the block uses.

lib/core/network_info/network_info.dart:


abstract class NetworkInfo 
            await hasInternetConnection();
      

lib/core/network_info/network_info_impl.dart:

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:injectable/injectable.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';
import 'package:my_injectable_project/core/network_info/network_info.dart';



@LazySingleton(as: NetworkInfo)
class NetworkInfoImpl implements NetworkInfo {
  final Connectivity connectivity;
  final InternetConnectionChecker internetConnectionChecker;

  const NetworkInfoImpl();

  @override
  Future<bool> get isConnected async {
    try {
      bool isDeviceConnected = false;
      
      final connectivityResult = await connectivity.checkConnectivity();
      debugPrint('Connectivity Result: $connectivityResult');

      if (connectivityResult != ConnectivityResult.none) 
            await hasInternetConnection();
      
      debugPrint('Device Connected: $isDeviceConnected');
      return isDeviceConnected;
    } catch (e) {
      debugPrint('Error checking network connection: $e');
      return false;
    }
  }

  
  Future<bool> hasInternetConnection() async {
    try {
      final response = await http.get(Uri.parse('https://www.google.com')).timeout(
        const Duration(seconds: 5),
      );
      if (response.statusCode == 200) {
        return true;
      }
    } catch (e) {
      debugPrint('Error checking internet connection: $e');
    }
    return false;
  }
}
  • @LazySingleton(as: NetworkInfo): This is a key interpretation. It enrolls NetworkInfoImpl As a singleinin that imposes it NetworkInfo When the interface getIt() Called, an instance NetworkInfoImpl Will be provided.

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

  • internetConnectionChecker.hasConnection: This package is much more reliable than just checking the network type, as the device can be “connected” to the Wi -Fi network without internet access. internet_connection_checker Confirmation AddressAps Actively a series of addresses.

  • hasInternetConnection(): A Fallback Function that applies HTTP directly to a reliable URL like Google. It provides an additional layer of verification.

Step 3: Create block for network connectivity

Block network status handles business logic to check and exclude appropriate state changes in the UI.

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

import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:my_injectable_project/core/network_info/network_info.dart';
import 'package:rxdart/rxdart.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'network_info_bloc.freezed.dart';
part 'network_info_event.dart';
part 'network_info_state.dart';


@injectable
class NetworkInfoBloc extends Bloc<NetworkInfoEvent, NetworkInfoState> {
  final NetworkInfo networkInfo;
  final Connectivity connectivity;
  late StreamSubscription<List> connectivitySubscription;

  NetworkInfoBloc({
    required this.networkInfo,
    required this.connectivity,
  }) : super(NetworkInfoState.initial()) {
    
    EventTransformer debounce(Duration duration) {
      return (events, mapper) => events.debounceTime(duration).flatMap(mapper);
    }

    
    on(
      _onCheckNetwork,
      
      transformer: debounce(
        const Duration(seconds: 1),
      ),
    );

    
    connectivitySubscription = connectivity.onConnectivityChanged.listen((connectivityResult) async {
      await Future.delayed(const Duration(seconds: 1)); 
      debugPrint('Connectivity Result after delay: $connectivityResult');
      add(const CheckNetwork());
    });
  }

  
  Future<void> _onCheckNetwork(
    CheckNetwork event,
    Emitter emit,
  ) async {
    final isConnected = await networkInfo.isConnected;
    
    if (state.networkStatus != isConnected) {
      emit(state.copyWith(networkStatus: isConnected));
    }
    debugPrint(
        'Network Status ==> ${isConnected ? "Data connection is available." : "You are disconnected from the internet."}');
  }

  @override
  Future<void> close() {
    
    connectivitySubscription.cancel();
    return super.close();
  }
}
  • EventTransformer debounce(Duration duration): This is a custom transformer. It uses rxdartdebounceTime Waiting for a certain period of inactivity before allowing the operator to take action. This network is perfect for preventing checks of checks.

  • connectivity.onConnectivityChanged.listen(...): This creates a stream purchase ConnectivityResult. Whenever the device’s contact status changes (for example, switch to mobile data from Wi -Fi), this chain eliminates a new value, resulting in our dynamic CheckNetwork Incident

  • _onCheckNetwork(...): This function is the heart of block logic. It makes calls networkInfo.isConnected The current status and then eliminates a new state if the status has changed.

  • close(): This procedure must be subdued with proper resources management. This is the place where we clean our StreamSubscription To avoid memory leaks.

Events and states

freezed A code is a breeding tool that makes it easy to create inaccessible data classes, which are essential for block patterns.

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

part of 'network_info_bloc.dart';

@freezed
class NetworkInfoEvent with _$NetworkInfoEvent {
  const factory NetworkInfoEvent.checkNetwork() = CheckNetwork;
}
  • @freezed: This interpretation is stimulus freezed To create a boiler plate code for this class.

  • const factory NetworkInfoEvent.checkNetwork() = CheckNetwork;: It describes the same event for our block, which is CheckNetwork.

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

part of 'network_info_bloc.dart';

@freezed
class NetworkInfoState with _$NetworkInfoState {
  const factory NetworkInfoState({required bool networkStatus}) = _NetworkInfoState;

  factory NetworkInfoState.initial() => const NetworkInfoState(
    networkStatus: true,
  );
}
  • const factory NetworkInfoState(...): This describes our state, which easily keeps A networkStatus Bowlin.

  • factory NetworkInfoState.initial(): A helpful factory to create the initial state of the block.

Run the code generator

To create *.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 look at your project for changes and automatically regenerate the necessary files.

Step 4: Connect the block with UI

Finally, we will connect our block to the UI of flurry to react to state changes.

In your central widget, for example, main.dartYou can access the block getIt.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:my_injectable_project/core/dependency_injection/injection.dart';
import 'package:my_injectable_project/features/network_info/bloc/network_info_bloc.dart';

void main() {
  
  configureDependencies('dev');
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    
    return BlocProvider(
      create: (context) => getIt(),
      child: MaterialApp(
        title: 'Network Checker Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const NetworkCheckerPage(),
      ),
    );
  }
}

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

  @override
  State createState() => _NetworkCheckerPageState();
}

class _NetworkCheckerPageState extends State<NetworkCheckerPage> {
  final NetworkInfoBloc networkInfoBloc = getIt();

  @override
  void initState() {
    super.initState();
    
    networkInfoBloc.stream.listen((state) {
      if (state.networkStatus) {
        toastInfo(
          msg: "Data connection is available.",
          status: Status.success,
        );
      } else {
        toastInfo(
          msg: "You are disconnected from the internet.",
          status: Status.error,
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Network Connectivity'),
      ),
      body: Center(
        child: BlocBuilder(
          builder: (context, state) {
            return Text(
              state.networkStatus
                  ? 'Connected to the Internet!'
                  : 'Disconnected from the Internet.',
              style: TextStyle(
                fontSize: 20,
                color: state.networkStatus ? Colors.green : Colors.red,
              ),
            );
          },
        ),
      ),
    );
  }
}
  • BlocProvider: It provides widgets NetworkInfoBloc For example, side by the widget tree, makes accessible through any child’s widget BlocProvider.of(context).

  • networkInfoBloc.stream.listen(...): in: initStateWe subscribe to the state stream of the block. Each time a new state is deleted (which occurs when the network status changes), our listener is triggered, and we can report the toast.

  • BlocBuilder: This widget is used to rebuild UI in response to state changes. It listens for new states NetworkInfoBloc And its rebuilding builder Function, updating Text Widget to reflect the current network status.

Step 5: Display toast notifications

fluttertoast The package provides an easy, platform-on-estate method to display non-interference messages.

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';

enum Status { success, error }

void toastInfo({
  required String msg,
  required 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: 16.0,
  );
}

This helpful function simplifies the toast process by allowing you to explain a message and status, which sets the background color.

Conclusion

By adding the power of the block pattern, with dependent injection get_it And injectableAnd strong network checking libraries, you can create a highly reliable and maintained network connectivity checker in your application.

This architecture ensures that your app is accountable for network changes and provides clean concerns, making your code base extended and easy to test.

References

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

The basic principle of flurry and dart:

  1. Official documents while fluttering: Provides a comprehensive leader about hoisting development, including widgets, state management, and contradictory programming.

  2. Dart Official Documents: Details Dart Language Features, including Asynchronus Programming Future And Stream.

Contacts and network checks:

  1. connectivity_plus Package on the package: Official documents for connectivity_plus Plugin, Network Contact Types Examine its use.

  2. internet_connection_checker The package on the gems of the flurry: Details internet_connection_checker The package, which confirms the original Internet access by pingling outdoor servers.

  3. http Package on the package: Official documents to make HTTP applications in dart and dumps.

Dependent Injection:

  1. get_it Package on the package: For official documents get_itA simple service locator for dart and flurry.

  2. injectable Package on the package: For official documents injectableFor a code generator get_it Which simplifies the dependence registration.

  3. State Management (Block): flutter_bloc Package on the package – Official documents for flutter_bloc Providing wedge and utility to implement the package, block patterns.

Instability and Code Generation:

  1. freezed Package on the package: For official documents freezedA powerful code generator to create an unmanned data class.

  2. build_runner Package on the package: Tools used to drive code generators injectable_generator And freezed.

Reaction Programming (RXDART) and Streams:

  1. rxdart Package on the package: Official documents for rxdart, which extends the stream of Dart with powerful operators debounceTime.

  2. Filter API Documents “Stream Class – Dart: Async Library”: Official Darty Documents for Stream Class

User feedback:

  1. fluttertoast Package on the package: Official documents for fluttertoast Package for displaying toast messages.

You may also like

Leave a Comment

At Skillainest, we believe the future belongs to those who embrace AI, upgrade their skills, and stay ahead of the curve.

Get latest news

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

@2025 Skillainest.Designed and Developed by Pro