Flutter Bloc Pattern

Prasanth
7 min readDec 30, 2021

Hello there! In this article we are going to focus on bloc pattern and how it is implemented in a flutter. Before we start, if you want a demo app? Here we go….Visit my following GitHub repository and make use of it :)

What is Bloc Pattern?

Bloc is a design pattern created by Google and announced at Google I/O ’18 to help separate business logic from the presentation layer and enable a developer to reuse code more efficiently. The Bloc pattern uses Reactive Programming to handle the flow of data within an app. This bloc pattern contains 3 main concepts:

  • Stream

A Stream is an order of asynchronous events. Instead of getting the next event when you ask for it, the Stream tells you there is an event when it is ready. The Stream provides the means to receive a sequence of events. Each event is either a data event, referred to as an element of the Stream, or an error event, a notification that something failed. When a Stream has emitted all its events, a single “done” event will notify the listener that they reached the end. So simply we can say it is like an output.

  • Sink

You add streams of event/data input into a Sink and listen to them as streams of data output through a Stream. So in a simple term, It is an Input.

  • StreamControllers

StreamControllers are manager objects that instantiate both a stream and a sink. It will work like a black box and do all the necessary works for you. There for this our processing.

So finally we can come to a conclusion that the Sink act like Input and accepts events/data and passed it to our business logic and then StreamController process on it and then Stream gives the output of event/data.

How To Integrate Bloc Pattern in Flutter?

Flutter uses a library called Bloc to achieve bloc pattern based state management. We don’t need any additional imports and once we create a flutter project, we can use this library directly.

First, create a flutter project and create a couple of dart files inside the lib folder. One file is for your bloc state management and the other file is for your bloc provider, and create a class inside both of your files. Here in my example I’m going to name those files as “app_bloc.dart” and “app_bloc_provider.dart” and also my classes will be “AppBloc” and “AppBlocProvider” respectively.

Let’s configure our bloc provider

Why we need a bloc provider?

We all know that our flutter app has many screens and most of the screen will deal with states. So we need to make sure that, all our screens in the app deals with the same instance of our bloc class without creating new instances. So our bloc provider will handle this scenario for us and make sure our bloc class is working like a charm with a single instance.

Modify your bloc provider similar to this
  • If the data held by this widget is the same as the data held by old widget, then we do not need to rebuild the widgets that inherited the data held by old widget. This will handle by updateShouldNotify method. So we don’t need to worry :)

NOTE: You can have multiple bloc files in your project. But the bloc provider should be a single file and if you need to deal with multiple blocs inside the bloc provider, Then you can define the other blocs similarly but needs to modify your static method as below.

Finally, wrap your entire child inside the “app.dart” with your bloc provider. Now you can use this bloc provider with any of your screens. That’s all about bloc provider.

It’s time for bloc configurations

Here I will create my bloc implementation in two different ways. Let’s try both of the methods and comes to a conclusion.

Method 01 (With BehaviorSubject)

Step 01: Install flutter pub add rxdart to work with BehaviorSubject

Step 02: Import necessary libraries

Step 03: Define your variable as BehaviorSubject. Because of the BehaviorSubject, your variable itself act as a StreamController. So you don’t need to create separate StreamController here.

Step 04: Create constructor and define your data

Once your bloc created, this method will call and define all the necessary data that you provide. According to this example, I assign 25 as my initial value for my age variable.

Step 05: Create Stream getter

ageStream will give you the _age value as a stream

Step 06: Create your necessary function

Here my target is to update age. So to achieve that, I create my update function which accepts the new age and assign the new age value to my age variable.

Step 07: Create a dispose function and close all your StreamControllers

dispose method use to release the memory allocated to variables when state object is removed.

Step 08: Create object for your bloc inside your UI Screen using bloc provider

If you use single bloc inside your bloc provider and your static method is exactly like mine, choose this way
If you use multiple bloc inside your bloc provider, then choose this way

Step 09: Now create a StreamBuilder and call your stream which created in your bloc

Step 10: Finally, call your method from bloc and have fun!

Method 02 (Without BehaviorSubject)

Step 01: Import async library

Step 02: Define your variable

Step 03: Create StreamControllers. You need to create a StreamController to represent your variable and need to create number of StreamControllers depends on your functionalities.

Here the _salaryStreamController is representing my variable and _updateSalaryStreamController is responsible for my updateSalary method which I am going to create in my future.

Note: If your stream controller will be used in multiple screen, then you must declare it using broadcast like above image. Or else if you are going to use it in a single place, then you can remove the broadcast.

Step 04: Create Stream and sink getters

salaryStream method will return the _salary value as a stream and the updateSalary, gets an input and will perform some tasks. So it is declared as StreamSink (StreamSink is nothing but a Sink)

Note: If your StreamController declared with broadcast, then you must Stream it via asBroadcastStream or else you can remove it.

Step 05: Create your necessary function

Here my target is to update salary. So to achieve that, I create my update function which accepts the new salary value and do the necessary calculation and assign the new salary value to my _salary variable.

Step 06: Create Constructor, Add Data and Listen to changes

Step 07: Create a dispose function and close all your StreamControllers

Step 08: Create object for your bloc inside your UI Screen using bloc provider like I created in my 1st method.

Step 09: Now create a StreamBuilder and call your stream which created in your bloc like I created in my 1st method.

Step 10: Finally, call your method from bloc.

Which method to choose?

You can see that the first method with the use of BehaviorSubject is a little bit easier than the 2nd method. Because in your 2nd method you have to create your own StreamControllers and need to work on broadcast. But in the 1st method, the BehaviorSubject itself do all the necessary things for you. So I personally recommend the BehaviorSubject approach.

Then why I waste my time on the 2nd method?

The 2nd approach is well suited when you need to work on complex functionalities and need to share those functionalities between several screens.

That’s the end of this article. Hope you enjoy!

--

--