Internet Connected… But Nothing Loads?" How I Solved This in Flutter Using BLoC (BLoC Part-4)

Internet Connected… But Nothing Loads?" How I Solved This in Flutter Using BLoC (BLoC Part-4)

FlutterPulse

This article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

Last month, I was working on a client project. It was a beautiful Flutter app — smooth animations, elegant screens, everything perfect.

The tester came to me in the evening

"Hey man… your app's stuck on the loading screen. But I'm on Wi-Fi. Full bars!"

He was connected to Wi-Fi, with a full signal. No airplane mode. No VPN. Everything looked fine.

I grabbed his phone, confused. Tried it myself—spinning loader. No data.

Then he said:

"It's weird though… sometimes this Wi-Fi says I'm connected, but nothing works. Even my browser can't load pages."

And that's when it hit me:

Just because your phone shows "Connected to Wi-Fi" doesn't mean there's actual internet speed.

Image collected from https://unsplash.com/

The Realization 🤔

Like many developers, I was using the connectivity_plus package to check internet status. It tells you if you're connected to Wi-Fi, mobile, or nothing at all.

But it doesn't tell you this:

Is the internet actually working?Can you load anything?Or is the connection dead, even if it shows "Connected"?

That's where the lightbulb moment happened 💡

I needed a smarter way to monitor internet status — not just connection type, but connection quality.

My Solution: Check REAL Internet Access

I wanted my app to:

  • Check if the user is connected (Wi-Fi, Mobile Data, or offline)
  • AND confirm there's actual internet speed
  • Change the UI based on the internet status

Let's see how I did it — step by step.

Step 1: Required Packages 📦

To make all this work, you'll need a few Flutter packages.

Here's how to add them:

  1. Open your Flutter project.
  2. Open the file called pubspec.yaml In the root of your project.
  3. Under dependencies:Add these lines:
dependencies:
cupertino_icons: ^1.0.8
flutter_bloc: ^9.1.1
equatable: ^2.0.7
connectivity_plus: ^6.1.4
http: ^1.4.0

Now, save the file and run the command in your terminal

flutter pub get

That will download and install all the packages.

Step 2: Create internet_event.dart (BLoC Events)

Events are like triggers in the BLoC pattern. They represent things that happen in your app or in the real world that should cause a change.

In this project, there are three possible events:

I. InternetConnectedEvent

This event is triggered when:

  • Your device is connected to either Wi-Fi or Mobile Data
  • And there's a successful response from Google (meaning the internet is truly working)
class InternetConnectedEvent extends InternetEvent {
final ConnectivityResult connectionType;
const InternetConnectedEvent({required this.connectionType});

@override
List<Object> get props => [connectionType];
}

II. InternetDisconnectedEvent

This event is triggered when:

  • Your device has no network connection at all.
  • Neither Wi-Fi nor mobile data is available.
class InternetDisconnectedEvent extends InternetEvent {
const InternetDisconnectedEvent();
}

III. InternetNoSpeedEvent

This event is triggered when:

  • The device is technically connected to Wi-Fi or mobile data.
  • BUT your app can't reach Google (or whichever site you're pinging).

This might happen if:

A Wi-Fi router is plugged in but has no internet from the ISP.

Mobile data has no signal despite being turned on.

class InternetNoSpeedEvent extends InternetEvent {
const InternetNoSpeedEvent();
}

The full event code is below.

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:equatable/equatable.dart';

abstract class InternetEvent extends Equatable {
const InternetEvent();
@override
List<Object> get props => [];
}

class InternetConnectedEvent extends InternetEvent {
final ConnectivityResult connectionType;
const InternetConnectedEvent({required this.connectionType});
@override
List<Object> get props => [connectionType];
}

class InternetDisconnectedEvent extends InternetEvent {
const InternetDisconnectedEvent();
}

class InternetNoSpeedEvent extends InternetEvent {
const InternetNoSpeedEvent();
}

Step 3: internet_state.dart (BLoC States)

States in BLoC represent what's happening right now in your app. Think of states as the current status of your internet connection.

In this project, there are four possible states:

I. InternetLoading

This is the initial state.

👉 When does this happen?

  • When the app first starts.
  • Before we know anything about the connection, yet.
class InternetLoading extends InternetState {}

II. InternetConnected

This state means:

  • Your device is connected to Wi-Fi or mobile data.
  • AND there's a valid internet connection (e.g. Google responds).

👉 When does this happen?

  • Right after a successful HTTP ping to Google.
  • Either via Wi-Fi or mobile data.
class InternetConnected extends InternetState {
final ConnectivityResult connectionType;

const InternetConnected({required this.connectionType});

@override
List<Object> get props => [connectionType];
}

III. InternetDisconnected

This state means:

  • Your device has no connection at all.
  • Not connected to Wi-Fi or mobile data.

👉 When does this happen?

  • When connectivity is lost completely.
  • No signal, airplane mode, or Wi-Fi turned off.
class InternetDisconnected extends InternetState {
final String message;

const InternetDisconnected({required this.message});

@override
List<Object> get props => [message];
}

IV. InternetNoSpeed

This is the most interesting state!

It means:

  • You're technically connected (Wi-Fi or mobile data).
  • But the internet is not reachable or too slow to respond.

👉 When does this happen?

  • When the router is plugged in but has no internet from the ISP.
  • When mobile data shows bars but you an't reach any sites.
  • When there's a network firewall blocking traffic.
class InternetNoSpeed extends InternetState {
final String message;

const InternetNoSpeed({required this.message});

@override
List<Object> get props => [message];
}

The full state code is below.

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:equatable/equatable.dart';

abstract class InternetState extends Equatable {
const InternetState();
@override
List<Object> get props => [];
}

class InternetLoading extends InternetState {}

class InternetConnected extends InternetState {
final ConnectivityResult connectionType;
const InternetConnected({required this.connectionType});
@override
List<Object> get props => [connectionType];
}

class InternetDisconnected extends InternetState {
final String message;
const InternetDisconnected({required this.message});
@override
List<Object> get props => [message];
}

class InternetNoSpeed extends InternetState {
final String message;
const InternetNoSpeed({required this.message});
@override
List<Object> get props => [message];
}

Step 4: Create internet_bloc.dart (BLoC Logic)

In internet_bloc.dartWe define a BLoC that subscribes to connectivity changes using connectivity_plus and sets up a periodic timer to check internet availability every few seconds. It sends an HTTP HEAD request to Google to verify real internet access. Based on the response or connectivity status, it dispatches one of three events—connected, disconnected, or no speed—which the BLoC handles to emit corresponding states. This ensures the UI reflects true internet conditions, not just network connection types.

import 'dart:async';
import 'dart:developer';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:http/http.dart' as http;
import 'internet_event.dart';
import 'internet_state.dart';

class InternetBloc extends Bloc<InternetEvent, InternetState> {
final Connectivity _connectivity;
late final StreamSubscription<List<ConnectivityResult>> _connectivityStreamSubscription;
late final Timer _internetCheckTimer;

InternetBloc({required Connectivity connectivity})
: _connectivity = connectivity,
super(InternetLoading()) {
on<InternetConnectedEvent>((event, emit) {
emit(InternetConnected(connectionType: event.connectionType));
});

on<InternetDisconnectedEvent>((event, emit) {
emit(const InternetDisconnected(message: 'No internet connection'));
});

on<InternetNoSpeedEvent>((event, emit) {
emit(const InternetNoSpeed(message: 'Connected, but no internet speed'));
});

_connectivityStreamSubscription = _connectivity.onConnectivityChanged.listen((connectivityResultList) {
_checkInternetSpeed(connectivityResultList.first);
});

_internetCheckTimer = Timer.periodic(const Duration(seconds: 5), (timer) async {
final result = await _connectivity.checkConnectivity();
_checkInternetSpeed(result.first);
});
}

Future<void> _checkInternetSpeed(ConnectivityResult result) async {
if (result == ConnectivityResult.mobile || result == ConnectivityResult.wifi) {
try {
final response = await http.head(Uri.parse('https://www.google.com'));
if (response.statusCode == 200) {
add(InternetConnectedEvent(connectionType: result));
} else {
add(const InternetNoSpeedEvent());
}
} catch (e) {
add(const InternetNoSpeedEvent());
}
} else {
add(const InternetDisconnectedEvent());
}
}

@override
Future<void> close() {
_connectivityStreamSubscription.cancel();
_internetCheckTimer.cancel();
return super.close();
}
}

Step 5: Setup main.dart (App Entry Point)

In main.dartWe set up the Flutter app by initializing the BLoC for internet checking and wrapping the entire app in a BlocProvider so that all widgets can access the internet state. We define the app's theme and launch the MyHomePage widget as the home screen, which will respond visually to changes in internet connectivity.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'internet_bloc.dart';
import 'home_screen.dart';

void main() {
runApp(const MyApp());
}

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

@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => InternetBloc(connectivity: Connectivity()),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const MyHomePage(),
),
);
}
}

Step 6: home_screen.dart (UI + State)

In home_screen.dartWe build the main user interface with an AppBar whose color changes based on the current internet state (connected, disconnected, or no speed). The screen shows buttons to navigate to three other screens, making it easy for users to explore the app while always reflecting the real internet status visually.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'internet_bloc.dart';
import 'screen_one.dart';
import 'screen_two.dart';
import 'screen_three.dart';

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

@override
Widget build(BuildContext context) {
final internetState = context.watch<InternetBloc>().state;

return Scaffold(
appBar: AppBar(
title: const Text('Home Screen'),
backgroundColor: internetState is InternetConnected
? Colors.blue
: internetState is InternetNoSpeed
? Colors.orange
: Colors.red,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {},
child: const Text('Screen One'),
),
ElevatedButton(
onPressed: () {},
child: const Text('Screen Two'),
),
ElevatedButton(
onPressed: () {},
child: const Text('Screen Three'),
),
],
),
),
);
}
}

🎨 Result? A Smarter App

Now, my app does what most apps don't:

✅ Shows blue AppBar when the internet is working
⚠️ Shows orange when connected but can't load (like router down)
❌ Shows red when offline

This is one of those "small but powerful" features that dramatically improve user experience.

If you've ever had a user say:

"But my phone IS connected to Wi-Fi!"

…this setup will save you time and face 😅

🙌 Let's Connect!

If you enjoyed this article and want to learn more about Dart, Flutter, and modern app development, feel free to connect with me:

Keep experimenting, stay curious, and happy Coding! 💙🚀

Report Page