Understand Bloc in 5 Minutes.

ยท

3 min read

  1. Definition: BLoC is a design pattern for managing state and handling business logic in Flutter applications.

  2. Key Components: It involves separating the presentation layer from the business logic layer and uses streams to communicate state changes.

  3. Implementation: BLoC typically consists of a data layer (BLoC class), events that trigger state changes, and UI components (like BlocBuilder) that react to those state changes.

We'll Try to understand Bloc using code examples, I'll show using connectivity.

We need to print texts and snack bar on the screen corresponding to the network changes(connected or disconnected).

Firstly we need to have a bloc folder which will have all the blocs required in our code, here we need only one bloc i.e. InternetBloc.

Inside InternetBloc folder we need to have three dart files(InternetBloc.dart, InternetState.dart, InternetEvent.dart).

InternetEvent.dart : Contains the event need to be emitted.

InternetState.dart : Contains the state to be added.

InternetBloc.dart : Contains the mapping between state and event.

//InternetState.dart

// contains all the states

abstract class InternetState {}

class InternetInitialState extends InternetState {}

class InternetGainedState extends InternetState {}

class InternetLostState extends InternetState {}
//InternetEvent.dart

// this file contains all the event which would be added to emit the corresponding
// states.

abstract class InternetEvent {}

// this class is used to make the connection between following classes.
// we also have declared this abstract class such that when we need to add the
// event type in bloc file we can write just this parent abstract class, rather
// than having to add all the event type ( not possible )

// cannot instantiate abstract classes
class InternetLostEvent extends InternetEvent {}

class InternetGainedEvent extends InternetEvent {}
//InternetBloc.dart

// this file would map the events with the states.

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:connectivity/connectivity.dart';
import 'internet_event.dart';
import 'intenet_state.dart';

class InternetBloc extends Bloc<InternetEvent, InternetState>
//this extends the bloc class
// also we need to give the type of event and state within <>
{
  // making the connectivity
  Connectivity _connectivity = Connectivity();
  // we need to end the listener to connectivity after the bloc ends
  // otherwise it may affect the performance because it'd keep running in the bg.
  StreamSubscription? connectivitySubscription;

  InternetBloc() : super(InternetInitialState()) {
    // intialise with initial state
    //adding the lost event and the lost state to be emitted
    on<InternetLostEvent>((event, emit) => emit(InternetLostState()));
    //adding the gained event and the gained state to be emitted
    on<InternetGainedEvent>((event, emit) => emit(InternetGainedState()));

    // adding lister to connectivity and checking if connected

    connectivitySubscription =
        _connectivity.onConnectivityChanged.listen((result) {
      if (result == ConnectivityResult.mobile ||
          result == ConnectivityResult.wifi) {
        // adding the gained event if connected to internet
        add(InternetGainedEvent());
      } else {
        // adding the lost event if not connected to internet
        add(InternetLostEvent());
      }
    });
  }
  @override
  Future<void> close() {
    // TODO: implement close
    connectivitySubscription?.cancel();
    return super.close();
  }
}
//HomeScreen.dart

import 'package:bloc_tutorial/blocs/internet_bloc/intenet_state.dart';
import 'package:bloc_tutorial/blocs/internet_bloc/internet_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          // bloc builder can change the ui, bloc listener can change the code
          // and bloc consumer can have both the listener and builder.
          child: BlocConsumer<InternetBloc, InternetState>(
            listener: (context, state) {
              if (state is InternetGainedState) {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text("Connected"),
                    backgroundColor: Colors.green,
                  ),
                );
              } else {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text("Disconnected"),
                    backgroundColor: Colors.red,
                  ),
                );
              }
            },
            builder: (context, state) {
              if (state is InternetInitialState) {
                return Text("Loading...");
              } else if (state is InternetGainedState) {
                return Text("Gained !!");
              } else {
                return Text("Lost !!");
              }
            },
          ),
        ),
      ),
    );
  }
}
//Main.dart

import 'package:bloc_tutorial/blocs/internet_bloc/internet_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'screens/HomeScreen.dart';

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

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

  @override
  Widget build(BuildContext context) {
    // we need to wrap the material app with blocprovider, as this
    // will provide the corresponding bloc to the child.
    return BlocProvider(
      create: (context) => InternetBloc(),
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        home: HomeScreen(),
      ),
    );
  }
}
ย