Search code examples
flutterdartriverpod

StateNotifer is providing intial state value (bool) in riverpod


Hi I am using riverpod to check internet connectivity across the app however the state notifier is giving intial state value only or shoul I saw its value is not changing. Also yes I am updating state you can see it in the code.

InternetProvider.dart:

import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart';
import 'package:riverpod/riverpod.dart';

class ConnectivityStatusNotifier extends StateNotifier<bool> {
  ConnectivityStatusNotifier() : super(false);

  void checkInternet() {
    final listener =
        InternetConnection().onStatusChange.listen((InternetStatus status) {
      if (status == InternetStatus.connected) {
        state = true;
      }
      else{
        state = false;
      }
    });
  }
}

final connectivityProvider =
    StateNotifierProvider<ConnectivityStatusNotifier, bool>((ref) {
  return ConnectivityStatusNotifier();
});

In HomeScreen.dart:

final internet = ref.watch(connectivityProvider);

final Widget floatingActionButton = FloatingActionButton(
      onPressed: () {
        print(internet);
      },
      child: const Icon(Icons.chat),
    );

Output

whether the internet is connected or not its always false

I tried this with connectivity_plus package as well but it also didn't worked. I have also tried this:medium.com this also didn't worked,this one also provides inital state as well which is connectivitystatus.connected.


Solution

  • First of all, when using the internet_connection_checker_plus package, you need to give permissions on the platforms:

    -> Android

    Add the following permissions to your AndroidManifest.xml file:

    <uses-permission android:name="android.permission.INTERNET" />
    

    -> macOS

    Add the following permissions to your macOS .entitlements files:

    <key>com.apple.security.network.client</key>
    <true/>
    

    Then I rethought your code a bit and wrote another one, more reactive and using Notifier instead of the legacy StateNotifier:

    final connectivityProvider = NotifierProvider<ConnectivityStatusNotifier, bool>(
      ConnectivityStatusNotifier.new,
    );
    
    class ConnectivityStatusNotifier extends Notifier<bool> {
      late InternetConnection _internetConnection;
    
      @override
      bool build() {
        _internetConnection = InternetConnection();
        final stream = _internetConnection.onStatusChange.listen(_statusListener);
    
        ref.onDispose(() {
          stream.cancel();
        });
    
        return false;
      }
    
      void _statusListener(InternetStatus status) {
        switch (status) {
          case InternetStatus.connected:
            state = true;
          case InternetStatus.disconnected:
            state = false;
        }
      }
    }
    

    Now you can do something in the interface to just listen for changes to the connectivityProvider. If desired, you can add an action button to snack:

    class MyApp extends ConsumerWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        ref.listen(connectivityProvider, (_, isConnected) {
          if (!isConnected) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('No internet connection')),
            );
          }
        });
    
        return const Text('Next are other widgets');
      }
    }
    

    It's not very clear in your code when you call checkInternet. The problem is that if you call it several times without canceling the previous subscription, you will get a small memory leak :) I assume that maybe you forgot to call this function altogether)