Networking
The Network Monitoring System provides a comprehensive solution for monitoring network connectivity in Flutter applications using Riverpod providers. It includes automatic network status checking, widget mixins for easy integration, and alert management.
- Automatic Network Monitoring: Periodic checks using
InternetChecker - Riverpod Integration: Clean state management with providers
- Widget Mixins: Easy integration with existing widgets
- Alert System: Automatic network alerts via
AlertManager - Error Handling: Robust error reporting and recovery
- Testing Support: Comprehensive test utilities
The main provider that manages network status monitoring:
// Access network state
final networkState = ref.watch(networkServiceProvider);
// Check if online
final isOnline = ref.watch(isOnlineProvider);
// Get current status
final status = ref.watch(networkStatusProvider);
Immutable state object representing network status:
class NetworkServiceState {
final NetworkStatus networkStatus;
bool get isOnline => networkStatus == NetworkStatus.online;
}
Three different mixins for different use cases:
class MyWidget extends StatefulWidget {
// ... widget implementation
}
class _MyWidgetState extends State<MyWidget> with NetworkMonitorMixin {
@override
bool get sendNetworkAlerts => true; // Enable alerts
@override
void onNetworkStatusChanged(NetworkStatus status) {
// Custom handling of network changes
print('Network changed to: $status');
}
@override
Widget buildWithNetworkMonitoring(BuildContext context, WidgetRef ref, Widget? child) {
final isOnline = ref.watch(isOnlineProvider);
return Scaffold(
appBar: AppBar(
title: Text(isOnline ? 'Online' : 'Offline'),
),
body: YourWidgetContent(),
);
}
}
class _MyWidgetState extends State<MyWidget>
with NetworkMonitorMixin, NetworkMonitorUtilsMixin {
void _handleRefresh() async {
// Force a network check
await forceNetworkCheck(ref);
// Check current status
if (isCurrentlyOnline(ref)) {
// Perform online actions
}
}
void _testOfflineMode() {
// Manually set status for testing
setNetworkStatus(ref, NetworkStatus.offline);
}
}
class _MyWidgetState extends State<MyWidget> with NetworkAwareMixin {
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, ref, child) {
final isOnline = this.isOnline(ref);
return Container(
color: isOnline ? Colors.green : Colors.red,
child: Text(isOnline ? 'Connected' : 'Disconnected'),
);
},
);
}
}
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class NetworkStatusWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isOnline = ref.watch(isOnlineProvider);
final status = ref.watch(networkStatusProvider);
return Card(
child: ListTile(
leading: Icon(
isOnline ? Icons.wifi : Icons.wifi_off,
color: isOnline ? Colors.green : Colors.red,
),
title: Text('Network Status'),
subtitle: Text('Status: ${status.name}'),
),
);
}
}
// Before
class _MyPageState extends State<MyPage> {
@override
Widget build(BuildContext context) {
return Scaffold(/* ... */);
}
}
// After
class _MyPageState extends State<MyPage> with NetworkMonitorMixin {
@override
Widget buildWithNetworkMonitoring(BuildContext context, WidgetRef ref, Widget? child) {
return Scaffold(/* ... */);
}
}
class _CustomNetworkWidgetState extends State<CustomNetworkWidget>
with NetworkMonitorMixin {
@override
bool get sendNetworkAlerts => false; // Disable automatic alerts
@override
bool get logNetworkChanges => true; // Enable logging
@override
void onNetworkStatusChanged(NetworkStatus status) {
super.onNetworkStatusChanged(status);
// Custom logic for network changes
switch (status) {
case NetworkStatus.online:
_syncData();
break;
case NetworkStatus.offline:
_enableOfflineMode();
break;
case NetworkStatus.unknown:
_showConnectivityWarning();
break;
}
}
}
class NetworkTestWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Column(
children: [
ElevatedButton(
onPressed: () {
final notifier = ref.read(networkServiceNotifierProvider);
notifier.forceCheck();
},
child: Text('Force Check'),
),
ElevatedButton(
onPressed: () {
final notifier = ref.read(networkServiceNotifierProvider);
notifier.updateStatus(NetworkStatus.offline);
},
child: Text('Simulate Offline'),
),
],
);
}
}
test('should update network status', () {
final container = ProviderContainer();
final notifier = container.read(networkServiceNotifierProvider);
// Set to online
notifier.updateStatus(NetworkStatus.online);
expect(container.read(isOnlineProvider), true);
expect(container.read(networkStatusProvider), NetworkStatus.online);
container.dispose();
});
testWidgets('should show correct UI based on network status', (tester) async {
await tester.pumpWidget(
ProviderScope(
child: MaterialApp(
home: MyNetworkWidget(),
),
),
);
// Find the provider container
final container = ProviderScope.containerOf(
tester.element(find.byType(MyNetworkWidget)),
);
// Simulate network change
final notifier = container.read(networkServiceNotifierProvider);
notifier.updateStatus(NetworkStatus.offline);
await tester.pump();
// Verify UI updates
expect(find.text('Offline'), findsOneWidget);
});
The network monitoring uses InternetChecker with configurable intervals:
// From internet_checker.dart
InternetChecker._internal()
: checkInterval = kCheckNetwork, // Normal check interval
checkTimeout = kCheckNetworkWhenTimeout, // Timeout duration
checkDownInterval = kCheckNetworkWhenDown, // Check interval when down
addresses = kNetworkCheckAddresses; // Custom check addresses
Network alerts are automatically sent to kAlertManager. To customize:
class _MyWidgetState extends State<MyWidget> with NetworkMonitorMixin {
@override
bool get sendNetworkAlerts => false; // Disable alerts
@override
void onNetworkStatusChanged(NetworkStatus status) {
// Send custom alerts
if (status == NetworkStatus.offline) {
showDialog(/* custom offline dialog */);
}
}
}
- NetworkMonitorMixin: Use when you need alerts and monitoring
- NetworkMonitorUtilsMixin: Use when you need advanced utilities
- NetworkAwareMixin: Use for simple status checking
@override
void onNetworkStatusChanged(NetworkStatus status) {
switch (status) {
case NetworkStatus.online:
// Resume operations
_resumeDataSync();
_hideOfflineIndicator();
break;
case NetworkStatus.offline:
// Pause operations
_pauseDataSync();
_showOfflineIndicator();
break;
case NetworkStatus.unknown:
// Handle uncertainty
_showConnectivityWarning();
break;
}
}
// Only monitor in widgets that need it
class _NonNetworkWidgetState extends State<NonNetworkWidget> {
// Don't use network mixins if not needed
}
// Use Consumer only where needed
Widget build(BuildContext context) {
return Column(
children: [
StaticWidget(), // No Consumer needed
Consumer(
builder: (context, ref, child) {
final isOnline = ref.watch(isOnlineProvider);
return NetworkDependentWidget(isOnline: isOnline);
},
),
],
);
}
@override
void onNetworkStatusChanged(NetworkStatus status) {
try {
// Handle network change
_handleNetworkChange(status);
} catch (e, stackTrace) {
LOG.e('Failed to handle network change', error: e, stackTrace: stackTrace);
// Fallback behavior
_handleNetworkError();
}
}
- Providers not updating: Ensure
ProviderScopewraps your app - Alerts not showing: Check
sendNetworkAlertsistrueandkAlertManageris initialized - Memory leaks: Ensure widgets using mixins properly dispose
- Network checks failing: Verify internet connection and check addresses
// Enable debug logging
@override
bool get logNetworkChanges => true;
// Force network check for debugging
final notifier = ref.read(networkServiceNotifierProvider);
await notifier.forceCheck();
// Check current status
final status = ref.read(networkStatusProvider);
print('Current network status: $status');
// Before
class _OldWidgetState extends State<OldWidget> {
bool _isOnline = false;
@override
void initState() {
super.initState();
_checkNetwork();
}
void _checkNetwork() async {
// Manual network checking code
}
}
// After
class _NewWidgetState extends State<NewWidget> with NetworkAwareMixin {
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, ref, child) {
final isOnline = this.isOnline(ref);
// Use isOnline directly
},
);
}
}
This network monitoring system provides a robust, scalable solution for handling network connectivity in Flutter applications with minimal boilerplate and maximum flexibility.
Successfully implemented a comprehensive network monitoring solution with RiverPod that includes:
- Core Network Service Provider with timer-based monitoring
- Widget Mixins for easy integration with StatefulWidgets
- Alert System Integration with kAlertManager
- Complete Documentation and examples
- Testing Infrastructure and validation
- NetworkServiceNotifier: StateNotifier that manages network status with timer-based periodic checking
- Multiple Convenience Providers: isOnlineProvider, isOfflineProvider, networkStatusProvider, etc.
- Timer Management: Automatic start/stop with 30-second check intervals
- Error Handling: Comprehensive error reporting and state management
- Immutable State Class: Simple data container for network status
- isOnline Getter: Convenience method for checking online status
- Uses NetworkStatus Enum: From core package for consistency
Three different mixin levels for various use cases:
- Automatic provider listening with ref.listen
- Alert generation via kAlertManager
- Lifecycle management (initState/dispose)
- Network state change callbacks
- Provider listening without automatic alerts
- Custom callback handling for network changes
- Flexible integration options
- Basic network status access
- Minimal overhead for simple use cases
- Easy integration for read-only network status
- FullNetworkMonitorWidget: Complete implementation with alerts
- BasicNetworkWidget: Simple network status display
- CustomNetworkWidget: Custom callback handling
- Unit Tests: Mock-based testing for core functionality
- Provider Integration Tests: Flutter test environment validation
- Validation: Successfully runs and passes all tests
- Complete Setup Guide: Step-by-step implementation
- Usage Examples: All three mixin patterns
- Best Practices: Performance and reliability guidelines
- Troubleshooting: Common issues and solutions
// Automatic 30-second interval checking
Timer.periodic(const Duration(seconds: 30), (_) async {
await checkNetworkStatus();
});
// Direct state access
final networkState = ref.watch(networkServiceProvider);
// Convenience providers
final isOnline = ref.watch(isOnlineProvider);
final isOffline = ref.watch(isOfflineProvider);
// Option 1: Full featured with alerts
class MyWidget extends StatefulWidget with NetworkMonitorMixin
// Option 2: Enhanced with custom callbacks
class MyWidget extends StatefulWidget with NetworkMonitorUtilsMixin
// Option 3: Simple read-only access
class MyWidget extends StatefulWidget with NetworkAwareMixin
// Automatic alerts sent to kAlertManager
void _sendNetworkAlert(bool isOnline) {
kAlertManager.send(NetworkAlertInfo(
isOnline: isOnline,
timestamp: DateTime.now(),
));
}
class MyNetworkWidget extends StatefulWidget with NetworkMonitorMixin {
@override
Widget build(BuildContext context) {
final networkState = networkServiceState;
return Text(networkState.isOnline ? 'Online' : 'Offline');
}
}
class CustomNetworkWidget extends StatefulWidget with NetworkMonitorUtilsMixin {
@override
void onNetworkChanged(NetworkServiceState state) {
if (!state.isOnline) {
// Handle offline state
showOfflineMessage();
}
}
}
// Add to main.dart providers
networkServiceNotifierProvider,
networkServiceProvider,
isOnlineProvider,
isOfflineProvider,
// ... other convenience providers
- Network check failures are caught and logged
- State remains in last known state during errors
- Timer continues running for automatic recovery
- 30-second check interval balances responsiveness vs battery life
- Providers use StateNotifier for efficient state updates
- Mixins provide lightweight integration options
- Timer management prevents memory leaks
- Configurable check intervals
- Network quality metrics
- Connectivity type detection
- Historical network state tracking
- Custom alert types and priorities