Here is the way you can build Network Aware applications
High level overview
Create a service that listen to Connectivity change events, for
example wifi, mobile and none (offline). This service will emit
NewtorkStatus (our custom class) into a stream every time the
Connectivity changes.
Create consumer for the above NetworkStatus stream that will be
notified everytime the NetworkStatus changes.
Based on the network status rebuild the HomeScreen to show either
online or offline contents.
Sounds tricky but its actually easy to implement, we will be using connectivity
& provider
package to our rescue.
Firstly configure our project to use above dependencies, edit pubspec.yaml
to include the dependencies -
dependencies:
flutter:
sdk: flutter
connectivity: ^3.0.6
provider: ^6.0.1
Run $ pub get
you synchronise all the dependencies.
Now we will create our own NewtorkStatusService
this service will use NetworkStatus
enumeration with two states Online
& Offline
to notify the Connectivity state.
network_status_service.dart
enum NetworkStatus {
Online,
Offline
}
Now our NetworkStatusService will use the Connectivity package to get status of current connection status (wifi, mobile, none) and based on that it will emit a new NetworkStatus to stream. Our final NetworkStatusService would look something like this -
network_status_service.dart
import 'dart:async';
import 'package:connectivity/connectivity.dart';
enum NetworkStatus { Online, Offline }
class NetworkStatusService {
StreamController<NetworkStatus> networkStatusController =
StreamController<NetworkStatus>();
NetworkStatusService() {
Connectivity().onConnectivityChanged.listen((status){
networkStatusController.add(_getNetworkStatus(status));
});
}
NetworkStatus _getNetworkStatus(ConnectivityResult status) {
return status == ConnectivityResult.mobile || status == ConnectivityResult.wifi ? NetworkStatus.Online : NetworkStatus.Offline;
}
}
Now we will create our won custom widget that will return either an onlineChild
or offlineChild
based on NetworkStatus value. Here we will use provider
package to get NetworkStatus. I would look something like this -
network_aware_widget.dart
import 'package:flutter/material.dart';
import 'package:flutter_network_aware_app/services/network_status_service.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
class NetworkAwareWidget extends StatelessWidget {
final Widget onlineChild;
final Widget offlineChild;
const NetworkAwareWidget({Key? key, required this.onlineChild, required this.offlineChild})
: super(key: key);
@override
Widget build(BuildContext context) {
NetworkStatus networkStatus = Provider.of<NetworkStatus>(context);
if (networkStatus == NetworkStatus.Online) {
return onlineChild;
} else {
_showToastMessage("Offline");
return offlineChild;
}
}
void _showToastMessage(String message){
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1
);
}
}
Here I am also using the FlutterToast
to show toast message (just to add some interactivity to app)
Now's the fun part we will bring all the pieces together to make our app respond to NetworkStatus value. We will use out custom made widget inside a StreamProvider
widget. The StreamProvider
will subscribe on the NewtorkStatusService networkStatusController stream and trigger a build on child components every time the NetworkStatus changes to Online
or Offline
. Here's how it will look -
home.dart
import 'package:flutter/material.dart';
import 'package:flutter_network_aware_app/services/network_status_service.dart';
import 'package:flutter_network_aware_app/ui/components/network_aware_widget.dart';
import 'package:provider/provider.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Network Aware App"),
),
body: StreamProvider<NetworkStatus>(
create: (context) =>
NetworkStatusService().networkStatusController.stream,
child: NetworkAwareWidget(
onlineChild: Container(
child: Center(
child: Text(
"I am online",
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.w600),
),
),
),
offlineChild: Container(
child: Center(
child: Text(
"No internet connection!",
style: TextStyle(
color: Colors.grey[400],
fontWeight: FontWeight.w600,
fontSize: 20.0),
),
),
),
),
),
);
}
}
As you can see we are wrapping our NetworkAwareWidget
inside a StreamProvider
of NetworkStatus
. StreamProvider also makes sure that on create it will subscribe to the NetworkStatusService controller stream.
Finally our app starting point main.dart
will look something like this -
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_network_aware_app/ui/screens/home_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(primaryColor: Colors.blue),
home: Home());
}
}
The application would work as follows -
I hope this helps you to build you own network aware app and components!