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:
connectivity_plus: A package to check the basic network contact (for example, Wi -Fi, mobile data, Ethernet).internet_connection_checker: A more reliable tool that confirms the Internet access to a leading URL actively ping a simple network check.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.
rxdartWithdebounce: To prevent excessive and high -speed network checks, which can be defective and remove the device’s battery.With a dependent injection
get_itAndinjectable: Clean, modular and for the test code base.State management with block and
freezed: Block patterns separate business logic from UI, andfreezedEase the creation of incredible states and events.Rivers: A reaction to the changes in a network status, enabling the “always listing” approach.
fluttertoast: Clear, non -interference to provide user feedback.
Let’s sink.
Table of contents:
Provisions
Before starting, make sure you have a basic understanding of it:
Fluttering and dart: The basic principles of making apps with flurry.
Unconstitutional programming: Ideas such as
asyncFor, for, for,.awaitAndFuture.Block patterns: The basic principles of block (business logic component) for state management.
Code generation: Use the package like
build_runnerTo 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:
get_itThere 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.injectableIs a code generation package that worksget_it. By explaining with your classes@injectableFor, for, for,.@lazySingletonOr@moduleFor, for, for,.injectableAutomatically writes boiler plate code to register his dependencyget_itFor 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, includingdebounceTimeWhich 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 worksinjectable.
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 exampleGetItIt can be accessed globally.@injectableInit: This interpretation is a signalinjectable_generatorThat this is the file where it should produce a dependent registration code.void configureDependencies(String env) => getIt.init(environment: env);: This function beginsget_itAnd 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 moduleinjectable. The module is useful to register third -party classes or create an example of classes, which require complex setups.@lazySingleton: This interpretation tellsinjectableCreating 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 enrollsNetworkInfoImplAs a singleinin that imposes itNetworkInfoWhen the interfacegetItCalled, an instance() NetworkInfoImplWill 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_checkerConfirmation 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: This is a custom transformer. It usesdebounce (Duration duration) rxdart‘debounceTimeWaiting 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 purchaseConnectivityResult. 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 dynamicCheckNetworkIncident_onCheckNetwork(...): This function is the heart of block logic. It makes callsnetworkInfo.isConnectedThe 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 ourStreamSubscriptionTo 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 stimulusfreezedTo create a boiler plate code for this class.const factory NetworkInfoEvent.checkNetwork() = CheckNetwork;: It describes the same event for our block, which isCheckNetwork.
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 AnetworkStatusBowlin.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 widgetsNetworkInfoBlocFor example, side by the widget tree, makes accessible through any child’s widgetBlocProvider.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 statesNetworkInfoBlocAnd its rebuildingbuilderFunction, updatingTextWidget 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:
Official documents while fluttering: Provides a comprehensive leader about hoisting development, including widgets, state management, and contradictory programming.
Dart Official Documents: Details Dart Language Features, including Asynchronus Programming
FutureAndStream.
Contacts and network checks:
connectivity_plusPackage on the package: Official documents forconnectivity_plusPlugin, Network Contact Types Examine its use.internet_connection_checkerThe package on the gems of the flurry: Detailsinternet_connection_checkerThe package, which confirms the original Internet access by pingling outdoor servers.httpPackage on the package: Official documents to make HTTP applications in dart and dumps.
Dependent Injection:
get_itPackage on the package: For official documentsget_itA simple service locator for dart and flurry.injectablePackage on the package: For official documentsinjectableFor a code generatorget_itWhich simplifies the dependence registration.State Management (Block):
flutter_blocPackage on the package – Official documents forflutter_blocProviding wedge and utility to implement the package, block patterns.
Instability and Code Generation:
freezedPackage on the package: For official documentsfreezedA powerful code generator to create an unmanned data class.build_runnerPackage on the package: Tools used to drive code generatorsinjectable_generatorAndfreezed.
Reaction Programming (RXDART) and Streams:
rxdartPackage on the package: Official documents for rxdart, which extends the stream of Dart with powerful operatorsdebounceTime.Filter API Documents “Stream Class – Dart: Async Library”: Official Darty Documents for
StreamClass
User feedback:
fluttertoastPackage on the package: Official documents forfluttertoastPackage for displaying toast messages.