Open
Description
Platform
iOS 18.5
Plugin
connectivity_plus
Version
6.1.4
Flutter SDK
3.29.3
Steps to reproduce
- Have a listener on certain page and use "connectivity.onConnectivityChanged.listen".
- use subscription.cancel() when disposed.
- Go to other screen and trigger checkConnectivity()
- The initial result is ConnectivityResult.none
- And if I trigger again the checkConnectivity() the result is now okay.
Code Sample
// MAIN.DART
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:developer' as developer;
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:connectivity_plus_example/connectivity_service.dart';
import 'package:flutter/material.dart';
import 'home_page.dart';
// Use the singleton connectivity instance
final Connectivity connectivity = ConnectivityService().connectivity;
void main() {
// Add error logging to catch any async errors
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details);
developer.log('Flutter error caught: ${details.exception}',
error: details.exception, stackTrace: details.stack);
};
runZonedGuarded(
() => runApp(const MyApp()),
(error, stack) {
developer.log('Uncaught error in app:', error: error, stackTrace: stack);
},
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0x9f4376f8),
),
home: const MyHomePage(title: 'Connectivity Plus Example'),
);
}
}
//HOME PAGE
import 'dart:async';
import 'dart:developer' as developer;
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dummy_page.dart';
import 'main.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<ConnectivityResult> _connectionStatus = [ConnectivityResult.none];
@override
void initState() {
super.initState();
developer.log('HomePage: initState called');
developer.log(
'HomePage: initState called connectivity instance: ${connectivity.hashCode}',
);
initConnectivity();
developer.log('HomePage: Setting up connectivity subscription');
}
@override
void dispose() {
developer.log('Subscription cancelled in HomePage');
super.dispose();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initConnectivity() async {
late List<ConnectivityResult> result;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await connectivity.checkConnectivity();
developer.log('HomePage result: $result');
} on PlatformException catch (e) {
developer.log('Couldn\'t check connectivity status', error: e);
return;
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) {
return Future.value(null);
}
return _updateConnectionStatus(result);
}
Future<void> _updateConnectionStatus(List<ConnectivityResult> result) async {
setState(() => _connectionStatus = result);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
elevation: 4,
),
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Spacer(flex: 2),
Text(
'Active connection types:',
style: Theme.of(context).textTheme.headlineMedium,
),
const Spacer(),
ListView(
shrinkWrap: true,
children: List.generate(
_connectionStatus.length,
(index) => Center(
child: Text(
_connectionStatus[index].toString(),
style: Theme.of(context).textTheme.headlineSmall,
),
)),
),
const Spacer(),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DummyPage(),
),
);
},
child: const Text('Navigate to Dummy Page'),
),
// TODO: await connectivity.checkConnectivity(); fixes the issue
// ElevatedButton(
// onPressed: () async {
// // Force reinitialize the connectivity instance
// await connectivity.checkConnectivity();
// // Then do your actual check after it's reinitialized
// // await initConnectivity();
// developer.log(
// 'status tapped: initState called connectivity instance: ${await connectivity.checkConnectivity()}',
// );
// },
// child: const Text('status'),
// ),
ElevatedButton(
onPressed: () async {
developer.log(
'status tapped: initState called connectivity instance: ${connectivity.hashCode}',
);
await initConnectivity();
},
child: const Text('check connectivity'),
),
const Spacer(flex: 2),
],
),
);
}
}
//Dummy Page
import 'dart:async';
import 'dart:developer' as developer;
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'main.dart';
class DummyPage extends StatefulWidget {
const DummyPage({Key? key}) : super(key: key);
@override
State<DummyPage> createState() => _DummyPageState();
}
class _DummyPageState extends State<DummyPage> {
final bool _isListening = false;
StreamSubscription<List<ConnectivityResult>>? _connectivitySubscription;
@override
void initState() {
super.initState();
_startListening();
developer.log(
'DummyPage: initState called - using connectivity instance: ${connectivity.hashCode}');
}
@override
void dispose() {
developer.log(
'Cancelling subscription in DummyPage with hashCode: ${_connectivitySubscription?.hashCode}');
_connectivitySubscription?.cancel();
developer.log(
'DummyPage: dispose called - using connectivity instance: ${connectivity.hashCode}');
super.dispose();
}
void _startListening() {
if (!_isListening) {
_connectivitySubscription =
connectivity.onConnectivityChanged.listen((result) {
developer.log(
'listening: $result',
name: 'DummyPage',
);
});
developer.log(
'startListening called in button press ${connectivity.hashCode}');
setState(() {
developer.log('setState called in DummyPage');
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Test Connectivity Subscription'),
elevation: 4,
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Test if events are received after cancellation',
style: Theme.of(context).textTheme.titleLarge,
),
),
Column(
children: [
ElevatedButton(
onPressed: () {
_startListening();
},
child: const Text('Start Listening'),
),
],
),
const SizedBox(height: 16),
Text(
'Status: ${_isListening ? 'Listening' : 'Not listening'}',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 16),
const SizedBox(height: 16),
Text(
'Note: Change your device connectivity (WiFi/Mobile data) to trigger events',
style: Theme.of(context).textTheme.bodySmall,
textAlign: TextAlign.center,
),
],
),
);
}
}
//Singleton
import 'package:connectivity_plus/connectivity_plus.dart';
class ConnectivityService {
// Singleton instance
static final ConnectivityService _instance = ConnectivityService._internal();
// Factory constructor to return the singleton instance
factory ConnectivityService() => _instance;
// Private constructor
ConnectivityService._internal();
// The single connectivity instance shared across the app
final Connectivity connectivity = Connectivity();
}
Logs
none
Flutter Doctor
✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0) [2.5s]
• Android SDK at /Users/user/Library/Android/sdk
• Platform android-35, build-tools 35.0.0
• ANDROID_HOME = /Users/user/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.6+-13368085-b895.109)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 16.4) [1,767ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 16F6
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [11ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2024.3) [11ms]
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 21.0.6+-13368085-b895.109)
[✓] VS Code (version 1.100.3) [9ms]
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.112.0
[✓] Connected device (5 available) [6.5s]
• sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64 • Android 14 (API 34)
(emulator)
• iPhone (mobile) • 00008030-001C2C9A0ED2402E • ios • iOS 18.5 22F76
• macOS (desktop) • macos • darwin-arm64 • macOS 15.5 24F74
darwin-arm64
• Mac Designed for iPad (desktop) • mac-designed-for-ipad • darwin • macOS 15.5 24F74
darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 137.0.7151.69
[✓] Network resources [533ms]
• All expected network resources are available.
Checklist before submitting a bug
- I searched issues in this repository and couldn't find such bug/problem
- I Google'd a solution and I couldn't find it
- I searched on StackOverflow for a solution and I couldn't find it
- I read the README.md file of the plugin
- I'm using the latest version of the plugin
- All dependencies are up to date with
flutter pub upgrade
- I did a
flutter clean
- I tried running the example project