This article will serve as a beginner’s guide to BLoC pattern. I will provide my own simple definitions and an example using this pattern in Flutter. By the end of this post, you should be able to understand how powerful it is and be able to use it in your projects.

What BLoC pattern really is

I will skip the formal definition of BLoC (Business Logic Component), but instead define what it is to me. BLoC pattern is a way of dividing and organizing code to make it reusable. That’s it. For now, don’t worry about streams, sinks, state management and other jargons of a BLoC.

BLoC pattern is really just another way of splitting your code into layers in such a way that each component of your code can be swapped and replaced while the main function of your app still works unchanged.

BLoC pattern is a way of dividing and organizing code to make it reusable.

Step by step process of how BLoC pattern works

Before we even go deep into the code, it is better if we actually know first how this pattern works. The main component of this pattern is the BLoC itself which contains a part of the app’s business logic. The following is a step by step process of how BLoC pattern works.

A component sends an event to a BLoC BLoC accepts the event and does something BLoC updates its state and publishes this state update to listeners All components that are listening does something about new state

Now, replace the component/s from the steps above with real objects such as UI widgets, repositories, services, data sources, other BLoCs, or any other components you can think of.

1. A component sends an event to a BLoC

2. BLoC accepts the event and processes something

3. BLoC updates its state and publishes this update to listeners

4. Every component listening to this BLoC does something

What do I get for using it?

Before you go changing the whole architecture of your Flutter app, I will first list all the things that I found very useful after using this pattern.

Makes your code reusable due to decoupling

A good library and IDE plugins for Flutter

Testable code

Makes your code reusable due to decoupling

The reason that BLoC is reusable is due to it following a reactive programming paradigm. If you are familiar with the old design patterns, BLoC can be seen as a fusion of event driven architecture, observer, and state machine patterns.

It means that the BLoC component itself receives events, does something and then finally updates its state. At the same time, other components such as user interface, repositories, or even other BLoCs may listen to these state updates and do something with it.

The main thing here is that the BLoC does not know anything about the components that send events to it and to components that listen to it. This property is what makes it decoupled with the rest of the other layers.

..the BLoC does not know anything about the components that send events to it and to components that listen to it.

This decoupling property makes your codebase reusable. If you want another UI to use your existing BLoC, go for it! The BLoC will be usable as long as the external components know which events to send. On the other hand, listeners of the BLoC just need to know how to handle state updates.

A good library and IDE plugins for Flutter

You can implement the BLoC pattern using Dart standard libraries. However, I would suggest using the bloc and flutter_bloc libraries written by Felix Angelov. For extensive tutorials, detailed explanations and complete examples, see the library’s homepage.

The bloc library allows you to easily implement the pattern by providing base classes for Events, States and the BLoC itself. The flutter_bloc library on the other hand provides Flutter widgets that react to the BLoC’s state changes.

Both Android Studio and Visual Studio Code have plugins that generate the BLoC boilerplate code for you. Just type the name of the BLoC and these plugins would generate a base class for your events and states. It will also create the BLoC class which processes the events and updates the state.

Testable Code

Like many of the common patterns in software development, BLoC pattern was created to with testing in mind.

Since UI and data repositories are outside of the BLoC, you can easily write unit tests for the BLoC itself using streams. The repositories and services that the BLoC uses should only be interfaces so that it can be easily mocked and be included in the test.

For more information about writing unit tests for Flutter in general, see this article I wrote a while back.

How to write unit tests in Flutter In this article, we will learn how to write unit tests in Flutter. I will walk through ways on how we could test normal data types, future data type and streams.

How about an example?

I will show you a very simple app that demonstrate how BLoC pattern works in Flutter. This app will be a fake music player app, where pressing the buttons will change the state of the BLoC.

Fake music player using BLoC pattern

Now, remember the step by step process of how BLoC pattern works above? Let’s rewrite it with a more concrete example such as our fake music player.

As a quick example, this is how BLoC would work if we send it a play event.

Play button is pressed and sends a play event to the music player BLoC Music player BLoC gets a play event, which in turn plays a music Music player BLoC changes its current state from idle state to playing state and publishes this state update to listeners toolbar and row of buttons widget The toolbar and row of buttons widget checks the new playing state and decides which text and buttons to show

The BLoC component

The main component of this pattern is the BLoC itself. BLoC needs to know one type of state and one type of event.

We first need to include two libraries in our project. These are the latest versions at time of writing.

dependencies: bloc: ^3.0.0 flutter_bloc: ^3.2.0

Your BLoC needs to extend from the Bloc base class and define which state and event it will use. It is also required to override the method mapToEventState and write the business logic in it. All of these are found in the bloc library.

The mapToEventState function is triggered asynchronously whenever an event is sent to the BLoC. The Bloc base class provides a method add(event) for sending events.

Do not directly call the mapToEventState function. Only send events to a BLoC using the add(event) function.

It is important to only use the add(event) method for sending events because there are additional checks and error handling provided by the library itself.

States and Events

States represent the state of the BLoC. At any point in time, there can only be one state in a BLoC. If you need multiple states for your app, you would need to use multiple BLoCs.

States may also contain data. In our music player example, The MusicPlayerPlaying state contains the title of the song being played.

Events on the other hand are the data being sent to the BLoC. These events are sent asynchronously and is queued when BLoC receives them. In our example, the PlayEvent contains the title of the song to play.

BLoC Logic

Now that we have defined the parts of the BLoC pattern, we can start adding the business logic of our music player.

First, notice that the BLoC requires an instance of MusicPlayer. This will be our actual music player, but in this example, it is just a stub and will do nothing.

Second part is the logic. In our mapEventToState method, we first check the type of event the BLoC received. Based on the event type, we do something accordingly. If it is a play event, we then extract the music title and pass the data to our music player.

Finally, we update the state of the BLoC using the yield keyword. If you notice, the mapEventToState returns a Stream of type state.

Doing a yield just means we are publishing this data to the listeners of this stream. In this example, it will be our Flutter widgets. On top of the that, the current BLoC state automatically changes to the last state yielded.

User Interface

As I have mentioned all throughout this article, the BLoC does not know anything about its listeners. If you look closely at our BLoC code, there are no references of any Flutter widgets. It means one or more widgets can listen to it and send events at the same time.

We utilise the BLoC pattern by using the flutter_bloc library. The library provides BLoC widgets which essentially reacts to state changes by the BLoC.

Since these bloc widgets are essentially Flutter widgets, you can just use them to wrap widgets and widget trees that you want to react base on the BLoC changes.

Setup

The first thing to do is wrap your widget tree with a BlocProvider. When you do this, all the widgets down the widget tree will be able to use the BLoC you will be using. Here is the setup for our music player BLoC.

In the example above, we instantiate the MusicPlayerBloc with an instance of a DummyMusicPlayer. The MainScreen will be our widget that contains the whole screen of the app.

What this setup does is that it makes the MusicPlayerBloc accessible to every widget under the MainScreen widget tree. We can then make BLoC widgets that reacts to state changes.

Reacting to state changes

Here is an example of how the AppBar in our music player app changes its text when the state of the BLoC changes.

We made the title of the AppBar into a BlocBuilder widget, which returns a certain widget according the the state.

It is important to note that every time the state of the music player bloc changes, this widget gets redrawn. The good thing is that it does not redraw the whole AppBar, but only the title widget.

The same thing is applied to the other buttons where we show or hide the buttons depending on the current state of the BLoC.

Sending events to BLoC

In our example, we send events through button presses. Although technically it can be from anywhere as long as we use the add(event) method from the BLoC.

In order to send an event to BLoC, we first need to get an instance of the BLoC. As long as this button is created under the widget tree where we initialized the BLoC, the instance of the BLoC can be accessed by using this code:

MusicPlayerBloc bloc = BlocProvider.of<MusicPlayerBloc>(context);

Complete User Interface

The whole screen layout and logic for state changes can be seen in here

There is nothing really strange going on with this code. BLoC pattern helps make our code readable. Here is a list of how the widgets are drawn according to state

State is Idle Hide the Stop Button Display Toolbar title as Music Player Change the first button to Play Button

State is Playing Update toolbar to display the title of the song playing Change the first button to a Pause Button Show the Stop Button

State is Paused Update toolbar to display ‘Paused’ Change the first button to a Play Button Show the Stop Button



And that’s all! You can find the complete project here in my github repository.

Summary

BLoC pattern is really useful when it comes to separating your Flutter code into layers. This pattern helps decouple your business logic from your UI, services and repositories. It also makes your code reusable, easy to read, and testable.

Useful Links