'Simple Bloc Pattern and Network Connection check

Thank you for checking out my question :). I appreciate it!

What I am trying to do

I am trying to check if the user has an internet connection or not. For this, I use the bloc pattern. I am just starting out and I don't know what to do with these errors.

What the error messages are

The relevant error-causing widget was: TestScreen Testscreen:file//filepath (etc,etc)

Another exception was thrown: Each child must be laid out exactly once. Another exception was thrown: Updated layout information required for RenderErrorBox NEEDS-LAYOUT NEEDS-PAINT to calculate semantics.

Another exception was thrown: Bad state: Future already completed.

I am new and these errors are overwhelming. These errors tell me nothing. I hope you can help me out!

Code

Homescreen


class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);
  static String routeName = '/home';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Homepage'),
        ),
        body: BlocProvider(
          create: (context) => NetworkBloc()..add(ListenConnection()),
          child: TestScreen(),
        ));
  }
}

class TestScreen extends StatelessWidget {
  const TestScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: BlocBuilder<NetworkBloc, NetworkState>(
        builder: (context, state) {
          if (state is ConnectionFailure) return Text("No Internet Connection");
          if (state is ConnectionSuccess)
            return Text("You're Connected to Internet");
          else
            return Text("");
        },
      ),
    );
  }
}

Network Block

class NetworkBloc extends Bloc<NetworkEvent, NetworkState> {
  NetworkBloc() : super(ConnectionInitial());

  late StreamSubscription _subscription;

  @override
  Stream<NetworkState> mapEventToState(NetworkEvent event) async* {
    if (event is ListenConnection) {
      _subscription = DataConnectionChecker().onStatusChange.listen((status) {
        add(ConnectionChanged(status == DataConnectionStatus.disconnected
            ? ConnectionFailure()
            : ConnectionSuccess()));
      });
    }
    if (event is ConnectionChanged) yield event.connection;
  }

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

Network Event

abstract class NetworkEvent {}

class ListenConnection extends NetworkEvent {}

class ConnectionChanged extends NetworkEvent {
  NetworkState connection;
  ConnectionChanged(this.connection);
}

Network State

abstract class NetworkState {}

class ConnectionInitial extends NetworkState {}

class ConnectionSuccess extends NetworkState {}

class ConnectionFailure extends NetworkState {}

I hope you can help me out. Thank you very much!



Solution 1:[1]

There are a lot of issues with your code so I'm not sure if I got all of them.

  • You should not call .add() if you don't have registered event handler
//This is how you should register an event handler

NetworkBloc() : super(ConnectionInitial()) {
  on<ListenConnection>((event, emit) {
    // TODO: implement event handler 
  });
}
  • You are overriding a function mapEventToState(), when it doesn't override any of inherited methods
//@override NO NEED OF OVERRIDE HERE
Stream<NetworkState> mapEventToState(NetworkEvent event) async* {
  if (event is ListenConnection) {
    _subscription = DataConnectionChecker().onStatusChange.listen((status) {
      add(ConnectionChanged(status == DataConnectionStatus.disconnected
        ? ConnectionFailure()
        : ConnectionSuccess()));
    });
  }
  if (event is ConnectionChanged) yield event.connection;
}

And I'm not sure if this is intended, but your mapEventToState() also never gets called and without any emit() methods your UI will never rebuild.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1