Flutter Bloc
Tags: flutter, dart, bloc, mobile
Published: 2023-03-03 13:09:19

## ***What is flutter bloc?***

Flutter bloc is one of the state management for Flutter applications. You can use it to handle all the possible states of your application in an easy way.

![https://user-images.githubusercontent.com/38296077/126981491-e13d63ec-932d-4640-a9c2-927259ce48a7.jpg](https://user-images.githubusercontent.com/38296077/126981491-e13d63ec-932d-4640-a9c2-927259ce48a7.jpg)

## Why Bloc?

**Bloc makes it easy to separate presentation from business logic, making your code *fast*, *easy to test*, and *reusable*.**

### Advantages

- Understand easily what’s happening inside your app.
- More structured code, Easily to maintain an test.
- Know and understand every state of your app.
- Work on a single, stable, popular and effective bloc codebase.

## ***How does it work?***

When you use flutter bloc you are going to create events to trigger the interactions with the app and then the bloc in charge is going to emit the requested data with a state

![https://miro.medium.com/max/720/0*EG9GW70kfdesSPRZ.webp](https://miro.medium.com/max/720/0*EG9GW70kfdesSPRZ.webp)

## Core Concepts of Bloc

- **Streams**
    
    <aside>
    💡 **A stream is a sequence of asynchronous data.**
    
    </aside>
    
    In order to use the bloc library, it is critical to have a basic understanding of **`Streams`**and how they work.
    
    **If you're unfamiliar with `Streams` just think of a pipe with water flowing through it. The pipe is the `Stream` and the water is the asynchronous data.**
    
    We can create a  **`Stream`**  in Dart by writing an **`async*`** (async generator) function.
    
    ```dart
    Stream<int> countStream(int max) async* {
        for (int i = 0; i < max; i++) {
            yield i;
        }
    }
    ```
    
    By marking a function as **`async*`** we are able to use the **`yield`** keyword and return a **`Stream`** of data. In the above example, we are returning a  **`Stream`** of integers up to the **`max`** integer parameter.
    
    Every time we **`yield`** in an **`async*`** function we are pushing that piece of data through the **`Stream`** .
    
    We can consume the above **`Stream`** in several ways. If we wanted to write a function to return the sum of a **`Stream`** of integers it could look something like:
    
    ```dart
    Future<int> sumStream(Stream<int> stream) async {
        int sum = 0;
        await for (int value in stream) {
            sum += value;
        }
        return sum;
    }
    ```
    
    By marking the above function as **`async`** we are able to use the **`await`** keyword and return a **`Future`** of integers. In this example, we are awaiting each value in the stream and returning the sum of all integers in the stream.
    
    We can put it all together like so:
    
    ```dart
    void main() async {
        /// Initialize a stream of integers 0-9
        Stream<int> stream = countStream(10);
        /// Compute the sum of the stream of integers
        int sum = await sumStream(stream);
        /// Print the sum
        print(sum); // 45
    }
    ```
    
    Now that we have a basic understanding of how **`Streams`** work in Dart we're ready to learn about the core component of the bloc package: a **`Cubit`** .
    
- **Cubit**
    
    <aside>
    💡 **A `Cubit` is a class which extends `BlocBase` and can be extended to manage any type of state.**
    
    </aside>
    
    A **`Cubit`** can expose functions which can be invoked to trigger state changes.
    
    ![https://bloclibrary.dev/assets/cubit_architecture_full.png](https://bloclibrary.dev/assets/cubit_architecture_full.png)
    
    **States are the output of a `Cubit` and represent a part of your application's state. UI components can be notified of states and redraw portions of themselves based on the current state.**
    
    - **Create A Cubit:**
        
        We can create a **`CounterCubit`** like:
        
        ```dart
        class CounterCubit extends Cubit<int> {
          CounterCubit() : super(0);
        }
        ```
        
        When creating a **`Cubit`**, we need to define the type of state which the **`Cubit`** will be managing. In the case of the **`CounterCubit`** above, the state can be represented via an **`int`** but in more complex cases it might be necessary to use a **`class`**instead of a primitive type.
        
        The second thing we need to do when creating a **`Cubit`** is specify the initial state. We can do this by calling **`super`** with the value of the initial state. In the snippet above, we are setting the initial state to **`0`** internally but we can also allow the **`Cubit`** to be more flexible by accepting an external value:
        
        ```dart
        class CounterCubit extends Cubit<int> {
          CounterCubit(int initialState) : super(initialState);
        }
        ```
        
        This would allow us to instantiate **`CounterCubit`**instances with different initial states like:
        
        ```dart
        final cubitA = CounterCubit(0); // state starts at 0
        final cubitB = CounterCubit(10); // state starts at 10
        ```
        
    - **State Changes:**
        
        <aside>
        💡 **Each `Cubit` has the ability to output a new state via `emit`.**
        
        </aside>
        
        ```dart
        class CounterCubit extends Cubit<int> {
          CounterCubit() : super(0);
        
          void increment() => emit(state + 1);
        }
        ```
        
        In the above snippet, the **`CounterCubit`** is exposing a public method called **`increment`**
        which can be called externally to notify the **`CounterCubit`** to increment its state. When **`increment`** is called, we can access the current state of the **`Cubit`** via the **`state`**
        getter and **`emit`** a new state by adding 1 to the current state.
        
        Note:
        
        The **`emit`** method is protected, meaning it should only be used inside of a **`Cubit`**.
        
- **Bloc**
    
    <aside>
    💡 **A `Bloc` is a more advanced class which relies on `events` to trigger `state` changes rather than functions. `Bloc` also extends `BlocBase` which means it has a similar public API as `Cubit`. However, rather than calling a `function` on a `Bloc` and directly emitting a new `state`, `Blocs` receive `events` and convert the incoming `events` into outgoing `states`.**
    
    </aside>
    
    - Create A Bloc:
        
        Creating a **`Bloc`** is similar to creating a **`Cubit`** except in addition to defining the state that we'll be managing, we must also define the event that the **`Bloc`** will be able to process.
        
        <aside>
        💡 **Events are the input to a Bloc. They are commonly added in response to user interactions such as button presses or lifecycle events like page loads.**
        
        </aside>
        
        ```dart
        abstract class CounterEvent {}
        
        class CounterIncrementPressed extends CounterEvent {}
        
        class CounterBloc extends Bloc<CounterEvent, int> {
          CounterBloc() : super(0);
        }
        ```
        
        Just like when creating the **`CounterCubit`**, we must specify an initial state by passing it to the superclass via **`super`**.
        
    - **State Changes:**
        
        **`Bloc`** requires us to register event handlers via the **`on<Event>`** API, as opposed to functions in **`Cubit`**. 
        
        An event handler is responsible for converting any incoming events into zero or more outgoing states.
        
        ```dart
        abstract class CounterEvent {}
        
        class CounterIncrementPressed extends CounterEvent {}
        
        class CounterBloc extends Bloc<CounterEvent, int> {
          CounterBloc() : super(0) {
            on<CounterIncrementPressed>((event, emit) {
              // handle incoming `CounterIncrementPressed` event
            })
          }
        }
        ```
        
        <aside>
        💡 **Tip**: an **`EventHandler`** has access to the added event as well as an **`Emitter`** which can be used to emit zero or more states in response to the incoming event.
        
        </aside>
        
        We can then update the **`EventHandler`** to handle the **`CounterIncrementPressed`** event:
        
        ```dart
        abstract class CounterEvent {}
        
        class CounterIncrementPressed extends CounterEvent {}
        
        class CounterBloc extends Bloc<CounterEvent, int> {
          CounterBloc() : super(0) {
            on<CounterIncrementPressed>((event, emit) {
              emit(state + 1);
            });
          }
        }
        ```
        
        In the above snippet, we have registered an **`EventHandler`** to manage all  **`CounterIncrementPressed`** events. For each incoming **`CounterIncrementPressed`** event we can access the current state of the bloc via the **`state`** getter and **`emit(state + 1)`**.
        

## Bloc vs Cubit

![Screen Shot 2023-02-01 at 7.39.54 PM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-01_at_7.39.54_PM.png)

- Cubit
    
    Cubit is a subset of the BLoC Pattern package that does not rely on events and instead uses methods to emit new states.
    
    So, we can use Cubit for simple states, and as needed we can use the Bloc.
    
    There are many advantages of choosing Cubit over Bloc. The two main benefits are:
    
    **Cubit** is a subset of **Bloc**; so, it reduces complexity. Cubit eliminates the event classes. Cubit uses emit rather than yield to emit state. Since emit works synchronously, you can ensure that the state is updated in the next line.
    
    note:
    
    • We don’t have streams, so no transformations.
    
    ![Screen Shot 2023-02-01 at 7.48.48 PM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-01_at_7.48.48_PM.png)
    
- Bloc
    
    When we use BLoC, there’s two important things: “Events” and “States”. That means that when we send an “Event” we can receive one or more “States”, and these “States” are sent in a **stream**
    
    - We have two streams here: Events and States; and that means that all things that we can apply to a Stream we can do it here. Transformations.
    - We can do long duration operations here, things like: API calls, database, compressions or some other complex things.
    
    notes:
    
    - If you send a lot of events for one BLoC could be difficult to track if you are not tracking them correctly.
    - Sometimes we want to receive this “state” synchronously, but with BLoC this is not possible.
    
    ![Screen Shot 2023-02-01 at 7.54.25 PM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-01_at_7.54.25_PM.png)
    

**Note:** 
BLoC uses mapToState and gives you a stream (async*). Cubit uses normal functions and gives you the result immediately or a Future (with async).

![Screen Shot 2023-02-01 at 7.52.41 PM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-01_at_7.52.41_PM.png)

## Flutter Bloc Concepts

### **BlocProvider**

![Screen Shot 2023-02-02 at 12.37.37 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-02_at_12.37.37_AM.png)

<aside>
💡 Is a flutter widget which creates and provides a Bloc to all of its children.

</aside>

- Is also known as as dependency injection.
- `BlocProvider` will provide a single instance of a Bloc to the subtree below it.
    
    ![Screen Shot 2023-02-02 at 12.43.04 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-02_at_12.43.04_AM.png)
    

```dart
// you must add flutter_bloc package dependency in pubspec.yaml
BlocProvider(
	create: (BuildContext context) => BlocA(),
	child: yourWidget(),
);

// The context in which a specific widget is built

```

we access it in a subtree like: 

```dart
BlocProvider.of<BlocA>(context);

// OR

context.read<BlocA>();
```

- By default, `BlocProvider` create the Bloc lazily
    
    meaning that the create function will get executed when the Bloc is looked up for via `BlocProvider`  of Bloc a context 
    
    note:
    
    To override this behavior and force the `BlocProvider` create function to be run immediately as soon as possible laze can be set to false inside the widget’s parameters like:
    
    ```dart
    BlocProvider(
    	create: (BuildContext context) => BlocA(),
    	laze: false,
    	child: yourWidget(),
    ); 
    ```
    
- `BlocProvider` handles the closing part of Bloc automatically so that where won’t be any stream leaks all over the place

Question

When we push a new screen into the navigation routing feature of flutter is the `BlocA` going to be available there too?

No, because there is another context  created on the new rout, a context which the `BlocProvider` doesn’t know yet.

so in order to pass the only instance of the Bloc to the new rout, we will use `BlocProvider.value()`

![Screen Shot 2023-02-02 at 1.07.29 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-02_at_1.07.29_AM.png)

```dart
BlocProvider.value(
	value: BlocProvider.of<BlocA>(context),
	child: newChild(),
);
```

Example:

build counter app with bloc

```dart
// in this app we use Cubit
// 1- create app states -> counter_states.dart
class CounterState{
int counterValue;
CounterState({
required this.counterValue,
});
}

// 2- create cubit -> counter_cubit.dart
class CounterCubit extends Cubit<CounterState> {
  CounterCubit() : super(CounterState(counterValue:0));

  void increment() => emit(CounterState(counterValue:state.counterValue + 1));

  void decrement() => emit(CounterState(counterValue:state.counterValue - 1));
}

// Ui 
class CounterApp extends StatelessWidget {
  const CounterApp({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => CounterCubit(), // -> create counter cubit
      child: MaterialApp(
				body:counterScreen(),
			),
    );
  }
}

//in counter screen you access increment and decrement methods in buttons like:

FloatingActionButton(
    child: const Icon(Icons.add),
    onPressed: () => context.read<CounterCubit>().increment(),//access increment
  ),

FloatingActionButton(
    child: const Icon(Icons.remove),
    onPressed: () => context.read<CounterCubit>().decrement(),//access decrement
  ),
```

The Question now is How do we receive the new state inside the UI ?, How do we rebuild specific text widget which prints out the counter value ?

It is now time to introduce the second important Flutter Bloc concept which is `BlobBuilder`

### **BlocBuilder**

<aside>
💡 A widget that helps Re-Building the UI based on Bloc state changes

</aside>

Re-Building a large chunk of the UI required a lot of time to compute, good practice would be to wrap the exact part of the UI you want to rebuild inside `BlocBuilder` 

![Screen Shot 2023-02-02 at 3.29.29 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-02_at_3.29.29_AM.png)

Ex:

If you have a text widget which updates from a sequence of emitted states and that text is inside a tone of Columns, Rows and other widgets , it is a huge mistake to rebuild all of them just to update the text widget 

 to rebuild only the text widget → wrap it inside `BlocBuilder` 

- `BlocBuilder` is a widget which requires a Bloc or Cubit and the builder function
    
    builder function → will potentially be called many time due to how flutter engine works behind the scenes and should be a pure function that returns a widget in response to a state.
    
    Pure Function → is a function return value depends only on the function’s arguments and no others.
    
    ![Screen Shot 2023-02-02 at 3.40.14 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-02_at_3.40.14_AM.png)
    
    So in this case our builder function should return a widget which only depend on the context and state parameters .
    
    ```dart
    BlocBuilder<BlocA,BlocAStates>(
    	builder: (context, state){
    		return widget;
    	}
    )
    ```
    
    If the Bloc or Cubit is not provided the `BlocBuilder` will automatically perform lookup for its instance using `BlocProvider` and the current build context.
    
    - you can use `buildWhen` parameter this should take in a function having the previous state and current state as parameters
        
        Ex:
        
        If text value in current state greater than the text value in previous state you can `return false` so that the Builder function won’t trigger and won’t rebuild UI
        
        ```dart
        BlocBuilder<BlocA,BlocAStates>(
        	builder: (context, state){
        		return widget;
        	}
        	buildWhen: (previous, current){}
        )
        ```
        

### BlocListener

has mainly the same structure as `BlocBuilder` but it is really deferent in many ways

<aside>
💡 Is a flutter widget which listens to any sate change as BlocBuilder does but instead of rebuilding a widget as BlocBuilder did with the builder function it takes a simple void function called listener which is called only once per state not including the initial state.

</aside>

There is also a `listenWhen` parameter function you can pass to tell the `BlocListener` when to call the listener function or not as build when parameter was for the `BlocBuilder` widget.

```dart
BlocListener<BlocA,BlocAStates>(
	listener: (context, state){
		debugPrint("do stuff have on BlocA's state")
	},
	child: widget,
)
```

🔄  In our Counter App:

We need to Re-Build text widget and print increment when click add button and decrement when click remove button, Let’s do this 

```dart
// rebuild text widget 
BlocBuilder<CounterCubit, CounterState>(
       builder: (context, state) {
           return Text(
              state.counterValue.toString(), // initial value = 0
		          style: Theme.of(context).textTheme.headlineLarge,
      );
   },
),

// to print in listener we need ro refactor CounterState and CounterCubit
// Let's do this
// refactor CounterState to add wasIncremented variable
class CounterState {
  int counterValue;
  bool? wasIncremented;
  CounterState({
    required this.counterValue,
    this.wasIncremented,
  });
} 

// refactor Cubit to change wasIncremented variable value on emit state 
class CounterCubit extends Cubit<CounterState> {
  CounterCubit() : super(CounterState(counterValue: 0));

  void increment() => emit(
        CounterState(
          counterValue: state.counterValue + 1,
          wasIncremented: true, // when click add button  
        ),
      );

  void decrement() => emit(
        CounterState(
          counterValue: state.counterValue - 1,
          wasIncremented: false, // when click remove button
        ),
      );
}

// Now you can access this variable when listen to state change 
	Scaffold(
		body: BlocListener<CounterCubit, CounterState>(
        listener: (context, state) {
          if (state.wasIncremented == true) {
            debugPrint('Incremented');
          } else {
            debugPrint('Decremented');
          }
        },
        child: CounterDesign(),
);

// Now We are done 
// Now you have created your first Flutter App with Bloc
```

Perhaps you are in our situation right now when you are updating UI using `BlocBuilder` and also print something using `BlocListener` isn’t there an easier way to do it of course there is, it is called `BlocConsumer` 

### BlocConsumer

<aside>
💡 Is a widget which combines both `BlocListener` and `BlocBuilder` into a single widget

</aside>

![Screen Shot 2023-02-02 at 4.51.42 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-02_at_4.51.42_AM.png)

### **BlocSelector**

<aside>
💡 Is a Flutter widget which is analogous to **`BlocBuilder`** but allows developers to filter updates by selecting a new value based on the current bloc state. Unnecessary builds are prevented if the selected value does not change. The selected value must be immutable in order for **`BlocSelector`**to accurately determine whether **`builder`**should be called again.

</aside>

If the **`bloc`**parameter is omitted, **`BlocSelector`**will automatically perform a lookup using  **`BlocProvider`** and the current **`BuildContext` .**

```dart
BlocSelector<BlocA, BlocAState, SelectedState>(
  selector: (state) {
    // return selected state based on the provided state.
  },
  builder: (context, state) {
    // return widget here based on the selected state.
  },
)
```

### **MultiBlocProvider**

<aside>
💡 Is a Flutter widget that merges multiple **`BlocProvider`**widgets into one.

</aside>

**`MultiBlocProvider`** improves the readability and eliminates the need to nest multiple  **`BlocProviders`**. 

Example without it:

```dart
BlocProvider<BlocA>(
  create: (BuildContext context) => BlocA(),
  child: BlocProvider<BlocB>(
    create: (BuildContext context) => BlocB(),
    child: BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
      child: ChildA(),
    )
  )
)
```

Example with it:

```dart
MultiBlocProvider(
  providers: [
    BlocProvider<BlocA>(
      create: (BuildContext context) => BlocA(),
    ),
    BlocProvider<BlocB>(
      create: (BuildContext context) => BlocB(),
    ),
    BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
    ),
  ],
  child: ChildA(),
)
```

### **MultiBlocListener**

<aside>
💡 Is a Flutter widget that merges multiple **`BlocListener`** widgets into one

</aside>

**`MultiBlocListener`** improves the readability and eliminates the need to nest multiple  **`BlocListeners` .**

```dart
// without it
BlocListener<BlocA, BlocAState>(
  listener: (context, state) {},
  child: BlocListener<BlocB, BlocBState>(
    listener: (context, state) {},
    child: BlocListener<BlocC, BlocCState>(
      listener: (context, state) {},
      child: ChildA(),
    ),
  ),
)
```

→ with **`MultiBlocListener`**

```dart
MultiBlocListener(
  listeners: [
    BlocListener<BlocA, BlocAState>(
      listener: (context, state) {},
    ),
    BlocListener<BlocB, BlocBState>(
      listener: (context, state) {},
    ),
    BlocListener<BlocC, BlocCState>(
      listener: (context, state) {},
    ),
  ],
  child: ChildA(),
)
```

### RepositoryProvider

<aside>
💡 Is a Flutter widget which provides a repository to its children via  **`RepositoryProvider.of<T>(context)`**

</aside>

The same exact widget as a `BlocProvider` the only difference being that it provides a single repository class instance instead of a single Bloc Instance.

⇒ It is used as a dependency injection (DI) widget so that a single instance of a repository can be provided to multiple widgets within a subtree

NOTE:

**`BlocProvider`** should be used to provide blocs whereas **`RepositoryProvider`** should only be used for repositories.

```dart
RepositoryProvider(
  create: (context) => RepositoryA(),
  child: ChildA(),
);
```

then from **`ChildA`** we can retrieve the **`Repository`** instance with:

```dart
// with extensions
context.read<RepositoryA>();

// without extensions
RepositoryProvider.of<RepositoryA>(context)
```

### **MultiRepositoryProvider**

<aside>
💡 is a Flutter widget that merges multiple **`RepositoryProvider`** widgets into one.

</aside>

⇒ **`MultiRepositoryProvider`** improves the readability and eliminates the need to nest multiple **`RepositoryProvider`** .

By using **`MultiRepositoryProvider`** we can go from:

```dart
RepositoryProvider<RepositoryA>(
  create: (context) => RepositoryA(),
  child: RepositoryProvider<RepositoryB>(
    create: (context) => RepositoryB(),
    child: RepositoryProvider<RepositoryC>(
      create: (context) => RepositoryC(),
      child: ChildA(),
    )
  )
)
```

To:

```dart
MultiRepositoryProvider(
  providers: [
    RepositoryProvider<RepositoryA>(
      create: (context) => RepositoryA(),
    ),
    RepositoryProvider<RepositoryB>(
      create: (context) => RepositoryB(),
    ),
    RepositoryProvider<RepositoryC>(
      create: (context) => RepositoryC(),
    ),
  ],
  child: ChildA(),
)
```

### **BlocObserver**

One added bonus of using the bloc library is that we can have access to all **`Changes`** in one place. Even though in this application we only have one **`Cubit`**, it's fairly common in larger applications to have many **`Cubits`** managing different parts of the application's state.

If we want to be able to do something in response to all **`Changes`** we can simply create our own **`BlocObserver`**.

```dart
class SimpleBlocObserver extends BlocObserver {
  @override
  void onChange(BlocBase bloc, Change change) {
    super.onChange(bloc, change);
    print('${bloc.runtimeType} $change');
  }
}
```

In order to use the **`SimpleBlocObserver`**, we just need to tweak the **`main`** function:

```dart
void main() {
  Bloc.observer = SimpleBlocObserver();
  CounterCubit()
    ..increment()
    ..close();  
}
```

The above snippet would then output:

```bash
Change { currentState: 0, nextState: 1 }
CounterCubit Change { currentState: 0, nextState: 1 }
```

You can observe a Cubit or Bloc Like:

```dart
// ObserveACubit
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);

  @override
  void onChange(Change<int> change) {
    super.onChange(change);
    print(change);
  }
}

// ObserveABloc
abstract class CounterEvent {}

class CounterIncrementPressed extends CounterEvent {}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) => emit(state + 1));
  }

  @override
  void onChange(Change<int> change) {
    super.onChange(change);
    print(change);
  }
```

## Bloc Architecture

First we ask the questions that are on your mind 

What is an Architecture?

What is all about?

Why we need an ArchItecture?

Let’s start 

We as human species can’t live without a predefined and stable architecture which is mainly our skeleton, imagine having all kinds of different classes, methods, functions, variables all over the place, this is definitely going to result in a total failure.

Now assimilate this to us humans, How would our life be if we only had our organs every one had to choose where to place their heart, their lungs, their kidneys as probably none of these people would have survived in this situation without organized structure and stable skeleton neither would have any of the apps built without a proper architecture, it’s as simple as that.

![Screen Shot 2023-02-03 at 12.57.33 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_12.57.33_AM.png)

so think of architecture as being the skeleton, the blueprint, the structure which keep all your code organized stable and easy to test and maintain.

Now Bloc Architecture is simply an architecture which has Bloc as it center of gravity.

![Screen Shot 2023-02-03 at 1.01.47 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.01.47_AM.png)

So not only is `Bloc` a `Design Pattern` and `State Management library` but it also an `Architecture Pattern`

![Screen Shot 2023-02-03 at 1.03.40 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.03.40_AM.png)

What we know for now is that for every interaction an user makes with the app through each UI there should be an event dispatched to the specialized Bloc or Cubit which will process it and will eventually emit a state that is going to rebuild the UI in a way so that the user gets a feedback of what’s going on with the app, The big unknown variable in all this equation is how Bloc processes the event and perhaps retrieves the necessary data to show to the user, Let me put it this for you almost every app now a days retrieves its data from the internet, so in order to link our Bloc based flutter app with the outer data layer, we need to add the data layer into our equation so that for example:

when Bloc receives a fetching event from UI it will request some data from internet, retrieve it as a response, parse it and return the data with a new state to the user.

Let’s talk about layers 

We can split this into three separated main layers which not surprisingly will depend one on another, so the UI is mostly seen as a `Presentation Layer` , The Bloc/Cubit as `Business Logic Layer`  and the last but not the least the app’s data as simply the `Data Layer`

![Screen Shot 2023-02-03 at 1.23.46 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.23.46_AM.png)

We’re going to start with `Data Layer` which is farthest from the user interface and work our way up to the `Presentation Layer`

### Data Layer

<aside>
💡 has Responsibility of retrieving  and also manipulating data from one or more sources whether we’re talking about network, Database, Request or other asynchronous sources.

</aside>

![Screen Shot 2023-02-03 at 1.28.37 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.28.37_AM.png)

The Date Layer has been split up inside three important sub-layers :

- Models
- Data Provider
- Repositories

They will also be dependent on one another.

![Screen Shot 2023-02-03 at 1.30.44 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.30.44_AM.png)

Suppose you want to build your own first app and you don’t know where to actually start programming the app, what is actually the first thing  you should code ?

The best way to start your app of course after you visually and technically designed it is by coding your models, but what exactly is a model?

⇒ Let’s start with model 

### Model

A model is as its name is implying a blueprint to the data your application will work with.

![Screen Shot 2023-02-03 at 1.36.58 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.36.58_AM.png)

is a nothing more than a class which contains the data the application itself will be dependent on.

Example → weather API

![Screen Shot 2023-02-03 at 1.41.24 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.41.24_AM.png)

they shouldn’t be identical to the data provider, Why?

think of what is going to happen if you have weather apis in your app as a source to your weather data their apis will set completely different jsons to your app perhaps on of them has the temperature inside a temp name field and the other one a temperature name field then you will need to parse them separately to your universal models, remember that inside many apps might be multiple data sources but it’s recommended to have only `one special data model`in which they will parsed.

![Screen Shot 2023-02-03 at 1.44.02 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.44.02_AM.png)

This means that models should be independent enough to get weather data from many different weather APIs.

![Screen Shot 2023-02-03 at 1.52.31 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_1.52.31_AM.png)

So now after you hopefully understood what a model is, it is time to move over to next sub-layer the `Data Provider`

### Data Provider

<aside>
💡 Data Provider’s responsibility is to provide raw data to its successor the repository sub-layer

</aside>

⏰  Let’s concentrate on the Data Provider for a moment..

A Data Provider is actually an API for you own app this means that it is going to be a class which contain different methods and these methods will serve as a direct communication way with the data sources

this where all the magic happens, this is where flutter asks for the required data straight from the internet, all your network requests like `http.get` , `[http.post](http://http.post)` , `put` , `delete` will go inside take in mind that the return type of these methods won’t to be the type of model you created earlier but rather of the type of row data you received from the data source which for example may be a type of json string

![Screen Shot 2023-02-03 at 2.10.48 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_2.10.48_AM.png)

the component in which we’ll have our model class is instantiated as objects is repository  

### Repository

<aside>
💡 Is mainly a wrapper around one ore more Data Providers, it’s safe to say that it’s the part of data layer

</aside>

Bloc communicates with similar to the other data layer sub parts 

- Repositories are also classes which contain dependencies of their respective data providers so for example:
    
    the weather repository will have a dependency on the weather provider with help of which we’ll call the `getRawWeather` method and retrieve the weather `RowData` .
    
    ![Screen Shot 2023-02-03 at 2.26.08 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_2.26.08_AM.png)
    
- Repository is where the model object will be instantiated with the `RowData` from the `DataProvider` or raw data which will be model data with `fromJson` methods.
- The Repository is also a perfect place for `Fine-Tuning` the data before giving it as a response to the Bloc, here you can filter it, sort it and do all kinds of last of last moment changes before it will be sent to the `Business Logic Layer` .

### Business Logic Layer

<aside>
💡 Is where Bloc and Cubit will be created inside your flutter app, its main responsibility is to respond to user input from the Presentation layer with new emitted state.

</aside>

- This layer is meant to be the mediator between the beautiful bright and colorful side of the UI and the dark dangerous and unstable side of the Data Layer
    
    ![Screen Shot 2023-02-03 at 2.31.30 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_2.31.30_AM.png)
    
- The Business Logic Layer is the last layer that can intercept and catch any errors from with in the Data Layer and protect the application from crashing.

Now since this layer is closely related to the data layer especially the repository sub-layer it can depend on one or more repositories to retrieve the data needed to build up the app state.

 

![Screen Shot 2023-02-03 at 2.38.32 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_2.38.32_AM.png)

🟢  Important fact:

You need to know and understand is that Bloc can communicate one with each other, Cubit can do this too, this is really important

So let’s say we have our previous weather Bloc and we also have an InternetBloc which emits states based on weather there is a stable internet connection or not

Supposedly your internet connection dies when you want to know the weather from your location inside the WeatherBloc, you can depend on the InternetBloc and subscribe to its stream of emitted states then react on every internet state emitted by the InternetBloc

![Screen Shot 2023-02-03 at 2.51.11 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_2.51.11_AM.png)

So in this case the InternetBloc would have emitted a no internet state down the stream the weather Bloc will listen to the stream and will eventually receive the no internet state, the WeatherBloc can also emit a state in response to this internet state letting the user know that there  is no internet connection.

🚫  Don’t Forget :]

⇒ The subscription to the Bloc needs to be closed manually by overriding the close method, We don’t any stream leaks inside our app

🎉  We have arrived at our final layer of the Bloc Architecture the `Presentation Layer`

### Presentation Layer

This layer sums up every thing related to the user inter face like `Widgets`, `User Input`, `Lifecycle events`, `animations` and so on  and so froth, also its responsibility in our case is to figure out how to render itself based on one or more Bloc State.

⇒ Most application flows will start with perhaps an app start event which triggers the app to fetch some data from the Data Layer 

For Example:

When the first screen of the app will be created inside this constructor there will be a WeatherBloc which adds the app started event so that some location based weather will be displayed on the screen.

![Screen Shot 2023-02-03 at 3.31.36 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_3.31.36_AM.png)

Great, Now we are finished all app layers 🎉

→ final structure of weather app

![Screen Shot 2023-02-03 at 3.41.05 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-03_at_3.41.05_AM.png)

Let’s talk about anther important topic in Bloc, which is `BlocTesting` 

## Bloc Testing

<aside>
💡 **Bloc was designed to be extremely easy to test.**

</aside>

Why do developers hate testing so much?

The answer is so simple, We hate testing because the application works fine without it, it seems like a reasonable answer right and indeed it is an application can work without testing but doesn’t mean we should disconsider it so badly.

Testing is in so many cases a life saver, it’s the hero nobody talks about on the news

so if you hate testing much, think of it as acute little dog which will be loyal to you and your app all the time, think of it as a layer which will bark whenever something breaks inside your app

![Screen Shot 2023-02-05 at 3.01.19 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-05_at_3.01.19_AM.png)

Now let me ask you something, have you ever worked on a big project in which wanted to add anew feature and you realize that after 2 or even 3 days of work despite the fact that the feature works perfectly fine it breaks other features in a completely different place inside your app or maybe have you thought if you ever want to delete a piece of code from within your app will this action be destructive or non-destructive to the app itself, How would you check if every thing is ok ?

after wards most of you will say that they will run the app and check every feature to see if every thing works well but i’m sure that some of you won’t even physically test it and live with the idea that nothing will break a conclusion which is fundamentally wrong.

![Screen Shot 2023-02-05 at 3.02.58 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-05_at_3.02.58_AM.png)

⇒ Keep that in mind.

So what if i tell you that there is something which will run a full checkup of every feature you wrote inside your app so that whenever you refactor your code

![Screen Shot 2023-02-05 at 3.11.07 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-05_at_3.11.07_AM.png)

you’ll be stress-free without having to worry about if it’s gonna crash or not, you have already guessed that, i’m talking about our body testing.

![Screen Shot 2023-02-05 at 3.13.09 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-05_at_3.13.09_AM.png)

Now the difference between Pros & Cons → becomes a problem of

![Screen Shot 2023-02-05 at 3.18.18 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-05_at_3.18.18_AM.png)

But is it worth it, I’ll let answer this question in the following minutes after we understand the structure and practice testing on our beloved Counter App

How could we implement a test for a feature?

Think of it logically, how would you test if something is working or not?

in big words a test is defined by how you will programmatically tell flutter to double check if the output given by a feature is equal to the expected response you planned on receiving an no other

![Screen Shot 2023-02-05 at 3.27.58 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-05_at_3.27.58_AM.png)

Now let’s switch to the coding part where i’ll show how testing works and after wards how to write tests inside your app.

👉  Let’s do it

Now you need to clone this repo → [CounterApp](https://github.com/HanySameh/FlutterBloc/tree/master/counter_app) and add `bloc_test` & `test` dependency

```yaml
dependencies:
  bloc_test: ^9.1.0
  test: ^1.22.0
```

in test folder we’ll have our test files, a little hint i can give you is that every feature of your app need to be tested in the first place inside the test folder should be kind of symmetrical to the features from within tour app, so all you have  to crate the folder symmetrically to the lib folder inside the test folder and add `_test` to the name of the file.

In this case we’ll have a `counter_cubit_test.dart` in which we’ll test out the functionality of our counter feature.

![Screen Shot 2023-02-06 at 5.09.41 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-06_at_5.09.41_AM.png)

👉  Remember that all the counter feature does is to increment or decrement a counter value based on which button is pressed by the user.

So inside the test file we need to start by create a `MainFunction` inside this main function we’ll go right ahed and create a group with the name of `CounterCubit`  

```dart
import 'package:test/test.dart';

void main() {
  group('CounterCubit', () {
    
  });
}
```

group → is actually a way of organizing multiple test for a feature.

For Example:

inside our CounterCubit group we’ll write all the necessary test for the counter feature.

In a group you can also share a common `setup` and `teardown` functions across all the available test 

```dart
setUp(() {});
tearDown(() {});
```

What is the purpose of these functions?

- Inside the `setup` function you can instantiate
    
    For Example: 
    
    The objects our tests will be working with, in our case, we’ll instantiate the `CounterCubit` so that access it later on in our test
    
    so `setup` is mainly as its name is implying a function which will be called to create and initialize the necessary data tests will work with.
    
    on the other hand `teardown` function
    

```dart
void main() {
  group('CounterCubit', () {
    late CounterCubit counterCubit;

    setUp(() {
      counterCubit = CounterCubit();
    });

    tearDown(() {
      counterCubit.close();
    });
  });
}
```

- `teardown` Function
    
    <aside>
    💡 Is a function that will get called after each test is run and if `group` it will apply of course only to the test in that `group` inside of this perhaps we can `close` the created `Cubit`
    
    </aside>
    

Now the time has finally come for us to write our first test which is going to be checking the `InitialState` of our `CounterCubit` to is equal to `CounterState` with a `CounterValue` of `Zero` .

We’re going this by creating a `test` function and give it a description which should denote the purpose of it, in this case in going to be `“initial state of CounterCubit is CounterState(counterValue:0)”` 

```dart
group('CounterCubit', () {
    late CounterCubit counterCubit;

    setUp(() {
      counterCubit = CounterCubit();
    });

    tearDown(() {
      counterCubit.close();
    });
    test('initial state of CounterCubit is CounterState(counterValue:0)', () {
      
    });
  });
```

How do we check this?

I told you earlier that the purpose of any test is to check that the output of the feature is actually equal to the expected output nothing else

To do this, all we need is the `except` function which will take two main important arguments ( the `actual value` returned by our `InitialState` and the `expected value` which we’re expecting to be received )

So our `InitialState` returned when the `Cubit` created will be `counterCubit.state` and the `expected value` should be a `CounterState` which has the `counterValue: 0` 

```dart
test('initial state of CounterCubit is CounterState(counterValue:0)', () {
     expect(counterCubit.state, CounterState(counterValue: 0));
});
```

We can run this test by typing `dart run` test in terminal 

```bash
//todo
```

OR rather by clicking the run button next to the `group` .

So if we run this test we will surprisingly receive a complete failure with this Message

```bash
Expected: <Instance of 'CounterState'>
  Actual: <Instance of 'CounterState'>
```

in which we expected a instance of `CounterState` and we actually receive an instance of `CounterState` , here you can actually start to understand why testing is such an amazing tool, it has already signaled us a problem with our app.

 👉  Remember that the application worked perfectly when we manually tested it, how come that test fails then

since it tell us that both the `expected` and `actual` output are instance of `CounterState` and we know that both should have a `Zero` value inside that means that the instances are still different somehow 

![Screen Shot 2023-02-05 at 4.46.38 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-05_at_4.46.38_AM.png)

and that’s due the fact that inside `Dart` language two instances of the same exact class aren’t equal even though they are basically identical this is happening because these two instances are stored in a different part of the memory and `Dart` compares their location in memory instead of their values hence making them not equal.

You can override this behavior really simple by using a really popular library you may have already heard about → `Equatable`

in the backend, `Equatable` is just a simple tool which overrides the `equal operator` and the `HashCode` for every class that extends it hence tricking Dart into comparing the instances by value rather than by where they’re placed in the memory.

So if you want the functionality of comparing to instances like we do in our test, `Equatable` is the way to go. 

[equatable | Dart Package](https://pub.dev/packages/equatable)

Ok, so all we need to do inside our app right now is to add The `Equatable` dependency in `pubspec.yaml` file 

```yaml
dependencies:
  equatable: ^2.0.5
```

And then `extend` the `CounterState` class with it

```dart
import 'package:equatable/equatable.dart';

class CounterState extends Equatable {
  final int counterValue;
  final bool? wasIncremented;
  const CounterState({
    required this.counterValue,
    this.wasIncremented,
  });
}
```

NOTE:

that now we’ll get a warning telling us that need to override the `props` of the `Equatable` class

 👉  props → are just a way of indicating `Equatable` which are the fields in our class that we want to be compared while applying the equal operator

so we’re gonna pass both the `counterValue` and `wasIncremented` attributes inside the props list

```dart
import 'package:equatable/equatable.dart';

class CounterState extends Equatable {
  final int counterValue;
  final bool? wasIncremented;
  const CounterState({
    required this.counterValue,
    this.wasIncremented,
  });

  @override
  List<Object?> get props => [counterValue, wasIncremented]; // <-
}
```

Now whenever we will compare two `CounterStates` , Dart will compare them attributes by attribute in order to see whether they’re equal or not.

so right now if you go back to our test file and run the test, the test should finally `pass` since our `expected` and `actual` `CounterState` had the same `counterValue` which is `Zero` .

![Screen Shot 2023-02-06 at 7.33.22 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-06_at_7.33.22_AM.png)

Now it is time for us to test out the functionality of the `Increment` and `Decrement` functions from inside our counter feature because these are the most important right

⇒ for this we’ll use the `blocTest` function from inside the `bloc_test` dependency.

We’ll use this because we need to test the output as a response to the `increment` or `decrement` functions.

- We’ll start with the test for the `increment` functionality
    
    So firstly we need to describe it properly 
    
    `“the CounterCubit should emit a CounterState(counterValue:1, wasIncremented:true) when the increment function is called”` 
    
     👉  To do this, we’ll use the trio parameters of `build` , `act`, `expect` from inside `blocTest` function.
    
    ```dart
    blocTest(
          'the CounterCubit should emit a CounterState(counterValue:1,'
    			'wasIncremented:true) when the increment function is called',
       build: null,
       act: null,
       expect: null,
    );
    ```
    
    - build
        
        <aside>
        💡 Is a function that will return `current instance` of the `CounterCubit` in order to make it available to the testing process
        
        </aside>
        
         `build: ()⇒counterCubit,`
        
    - act
        
        <aside>
        💡 Is a function that will take the `cubit` and will return the `action` applied on it.
        
        </aside>
        
        in our case is the `increment` function → `act: (cubit)⇒ cubit.increment()`
        
    - expect
        
        <aside>
        💡 Is a function that will return an `iterable list` which will verify if the order of the state and the actual emitted state correspond with the emitted ones and no other.
        
        </aside>
        
        the `counterCubit` emits only a single state in this example we’ll place it inside the list accordingly
        
        `expect: ()⇒ [const CounterState(counterValue: 1, wasIncremented: true)],`
        
    
    ```dart
    blocTest(
        'the CounterCubit should emit a '
        'CounterState(counterValue:1, wasIncremented:true)'
        ' when the increment function is called',
      build: () => counterCubit,
      act: (cubit) => cubit.increment(),
      expect: () => [const CounterState(counterValue: 1, wasIncremented: true)],
    );
    ```
    
- test `decrement` function
    
    The same procedure applies also to decrement function, the only difference being that will `act` by calling the `decrement`  function and that will `expect` a `CounterState` with a `counterValue of -1` inside of `1` since we subtract 1 from the initial `counterValue` .
    
    ```dart
    blocTest(
        'the CounterCubit should emit a '
        'CounterState(counterValue:-1, wasIncremented:false)'
        ' when the decrement function is called',
      build: () => counterCubit,
      act: (cubit) => cubit.decrement(),
      expect: () =>
            [const CounterState(counterValue: -1, wasIncremented: false)],
    );
    ```
    

Let’s run all the test now 

![Screen Shot 2023-02-06 at 8.21.19 AM.png](Flutter%20Bloc%20dd67c4da85364af8b95ad111152caf8f/Screen_Shot_2023-02-06_at_8.21.19_AM.png)

Every Thing Passed  🎉  🎉

⇒ Now we can know for sure that the `CounterCubit` works as it should.

🤔 Think about this scenario for example:

Let’s say you were moved away from this project and another guy comes into place to continue the development, he doesn’t know Dart that well and he think that the `Equatable` package is not needed and that application can work just fine without it so he refactors the code, runs the app and indeed the app is still working perfectly but underneath if we run the `CounterCubit` test we can see that if there would be apart inside our app comparing two identical states, the output would have been completely different.

this is exactly why app testing shouldn’t be skipped, it may seem like the refactoring works fine but in reality it isn’t.

so i guess now you understood why it’s worth spending the extra time writing tests for user app.

---

- Resources
    - playlist
        
        [Introduction to "BLoC - from Zero To HERO" Series](https://www.youtube.com/watch?v=w6XWjpBK4W8&list=PLptHs0ZDJKt_T-oNj_6Q98v-tBnVf-S_o&index=1)
        
    - Bloc Library (official website) → recommended
        
        [Bloc State Management Library](https://bloclibrary.dev/#/gettingstarted)
        
- Source Code of projects with Bloc
    - [FlutterBloc](https://github.com/HanySameh/FlutterBloc)
    - [BlogClubApp](https://github.com/HanySameh/FlutterChallenges/tree/master/challenge_2)