Flutter BLoC Tutorial: State Management using BLoC Pattern



Document

What is BLoC?

BLoC is the abbreviation of the word Business Logic Components It aims to isolate the business logic
of an application from its User Interface, making the application’s code simpler, flexible,
adaptable, and capable of being tested.

  • Developed by: Felix Angelov
  • Sponsors: Very Good Ventures, Stream, Miquido
  • Version: flutter_bloc: ^8.0.1(at the time of writing article)

Pros & Cons of BLoC Design Pattern

Before we move on to the Flutter Block tutorial Let’s look at some of the advantages and
disadvantages of the block design pattern.

Pros of Using BLoC

Great documentation of various
scenarios.

Separates the business logic
from the UI which makes the code understandable.

It makes the product more
tastier.

It is simple to track the
states that an app has gone through.

Cons of Using BLoC

The learning curve is steep.

Not recommended for
applications with simple requirements.

A little more boilerplate
code, but it is easily handled with extensions.

Flutter BLoC Tutorial Goal

We will create a basic application to demonstrate how the BLoC utilizes streams to manage state and
create a few tests for the block.

We will create a basic application to demonstrate how the BLoC utilizes streams to manage state and
create a few tests for the block.

Initial Setup

Make sure to install the bloc extension in your editor; it will help create all boilerplate code and
files required for the project(right-click on the lib folder, and it will give you the option for
generation bloc for your project).

Make sure to match your pubspec.yaml file with mine to avoid any issues.

Want to have easy and hustle-free Flutter application development?

Neo Infoway is waiting for you! Contact us today to hire a Flutter developer to meet the requirements
of your project with outstanding problem-solving abilities.

Understanding BLoC Concepts: Events and States

To understand the way that blocks work We must know what constitutes states and events.

events:
These are the inputs that an
app can receive (like pressing a button to load images, inputs for text, or any other inputs
from users that our application might wish to get).

State:
State is the state of the application, and can be altered according to an event that is
received.

Bloc manages these states and events, i.e., it is able to take an entire flow of Events and convert
them into streams of States as output.

Creating an Event

                    
                        @immutable
                        abstract class AppBlocEvent {
                         const AppBlocEvent();
                        }
                        @immutable
                        class ChangeTextEvent extends AppBlocEvent {
                         const ChangeTextEvent();}
                    
                

Moving forward to the Flutter Block Tutorial. We have made an event called ChangeTextEvent which will
be fired whenever the button is pressed.

We use an abstraction of the AppBlocEvent Class since Bloc is expecting a single occasion to add to
its stream. However, since there could be multiple events running in an app, we design an abstract
class and then extend it when we need to add any new event and pass on multiple events to Bloc.

Creating a State

Event and State Management using BLoC Pattern

                    
                        class AppBlocBloc extends Bloc {
                            final List textList = [
                              'Initial Text',
                              'Changed Text',
                              'Changed Again',
                            ];
                            AppBlocBloc() : super(const AppState.empty()) {
                              on((event, emit) {
                                try {
                                  int newIndex = state.index + 1;
                                  if(newIndex >= textList.length) {
                                    newIndex = 0;
                                  }
                                  emit(
                                    AppState(
                                      index: newIndex,
                                      text: textList[newIndex],
                                    ),
                                  );
                                } on Exception catch (e) {
                                  // ignore: avoid_print
                                  print(e);
                                }
                              });
                            }
                           }
                           
                

Explanation

This is the section which contains the software.

When a it is added into the stream
with clicking a button. It gets the event, i.e. the information you wish to share with the
triggering events, you are able to access via this(like event.any_info which requires you to
alter your event’s class to reflect this) emit is used to generate an event state specific to
that event.

When a it is added into the stream
with clicking a button. It gets the event, i.e. the information you wish to share with the
triggering events, you are able to access via this(like event.any_info which requires you to
alter your event’s class to reflect this) emit is used to generate an event state specific to
that event.

state.index allows you to see the
state that is currently in the application’s state.index. It lets you see the current state of
the.

emit(AppState (…)): emit (…) is
used to generate new states and triggers the rebuilding part of the built() build() function.

Connect the pieces.

At present the events, states, blocks and our application’s UI are not linked to each other in any
manner. Let’s get them all connected.

Providing our BLoC

                    
                        import 'package:flutter/material.dart';
                        import 'package:flutter_bloc/flutter_bloc.dart';
                        import 'package:text_change/text_controller.dart';
                        import 'bloc/app_bloc_bloc.dart';
                        import 'bloc/app_bloc_state.dart';
                        class App extends StatelessWidget {
                          const App({Key? key}) : super(key: key);
                          @override
                          Widget build(BuildContext context) {
                            return MaterialApp(
                              title: 'Flutter Demo',
                              theme: ThemeData(
                                primarySwatch: Colors.blue,
                              ),
                              home: BlocProvider(
                                create: (context) => AppBlocBloc(),
                                child: Scaffold(
                                  appBar: AppBar(
                                    title: const Text('Text Change'),
                                  ),
                                  body: BlocConsumer(
                                    listener: (context, state) {},
                                    builder: (context, state) {
                                      return Text Controller(
                                        text: state.text,
                                      );
                                    },
                                  ),
                                ),
                              ),
                            );
                          }
                        }
                    
                

Explanation: App.dart

BlocProvider (…): We use it to display an instance of our block by placing it under the base of the
application to make it accessible to all users.

Create:
It creates the version of our AppBloBloc.

BlocConsumer
(…): It is the place in which everything takes place.

builder:
‘s responsible for creating it’s UI which is then rebuilt with every state changes.
blocConsumer also includes listenWhen and buildWhen that, like the name suggests, can be
customized to respond to specific state changes.

Triggering the Event and States

                    
                        class TextChangeController extends StatelessWidget {
                            final String text;
                            const TextChangeController({Key? key, required this.text}) : super(key: key);
                            @override 
                            Widget build (BuildContext context) { 
                                  return Column
                                     children:  [ 
                                        TextChange(
                                           text: text, 
                                        ), // TextChange 
                                       ElevatedButton( 
                                           onPressed: () =>
                                                context.read().add(const ChangeTextEvent()), 
                                          child: const Text('Change Text'), 
                                     ), // ElevatedButton 
                                  ), // [ ] 
                               ); // Column
                              )
                            )
                            
                

In this case, we’ve included the event called ChangetTextEventonto an event’s stream which triggers a
state change that triggers the rebuilding of BlocConsumer’s builder() inside BlocConsumer and then
the modified text will show to the right of the screen.

You’ve got it You’re done! With a separate UI with business logic you can alter the UI code, and then
connect the Bloc into. It will operate in the same way.

Testing the BLoC Design Pattern

For testing the bloc, you require two packages:

  • bloc_test
  • flutter_test

Simply go to the folder for testing, make the app_bloc_test.dart file and begin writing the
test.Inside we’ll test two requirements:

Initial state of application i.e AppState.empty().State changes when the button is pressed.

                            
                                void main() {
                                    blocTest(
                                      'Initial State',
                                      build: () => AppBlocBloc(),
                                      verify: (appState) =>
                                          expect(appState.state, const AppState.empty(), reason: 'Initial State'),
                                    );
                                    blocTest(
                                      'emits [MyState] when MyEvent is added.',
                                      build: () => AppBlocBloc(),
                                      act: (bloc) => bloc.add(const ChangeTextEvent()),
                                      expect: () => const [
                                        AppState(
                                          index: 1,
                                          text: 'Changed Text',
                                        ),
                                      ],
                                    );
                                   }
                                   
                        

Explanation

  • blocTest is a part of the package bloc_test.
  • Build() It returns an example of AppBlocBloc().
  • Expect and verify in the sense that they are in line with the state expect(actual
    matcher, actual).
  • Act: To insert an event to the stream

Github Repository: Flutter BLoC Simple Example

Feel free to copy your repository the flutter-bloc demo and begin to play around using the code.

Table of Contents

Tags Cloud

Angular Developers
Angular Development Company
Angular Development Services
ASP.Net Application Development
ASP.NET Boilerplate Development
Company

ASP.NET Boilerplate Development
Services

ASP.Net Core Development Services
ASP.Net Developers
ASP.NET Development Advantages
ASP.NET Development Services
ASP.NET Development Solutions
ASP.Net
MVC

ASP.Net
Programmers

ASP.Net Zero
ASP.Net Zero
Developers

ASP.NET Zero
Development Services

C Sharp Developers
C Sharp
Development

C# Developers
C# Development
Company

C# Development
Services

Neo Infoway
Custom Application
Development

Custom Software Development
Solution

Hire .Net Developers
Hire Angular Web and App Developers
Hire ASP.Net Developers
Hire SharePoint Developers
Ideas Software
Kentico Development Company
Kentico Development Services
Kentico Web Developer
Responsive Web Design
SharePoint Developers
SharePoint Development Services
UI Designer
UI/UX Design Services
Umbraco Development Company
Umbraco Development Services
UX Designer
Web Design Services
Web Design Solutions
Web Designers
Web Designing
Website Design Agency

Frequently Asked Questions (FAQs)

What is BLoC
and why is it used for state management in Flutter?

BLoC (Business Logic Component) is a design pattern used for managing
state in Flutter applications. It helps separate business logic from UI components, making
code more modular, testable, and maintainable. BLoC pattern is widely used in Flutter for
its simplicity and scalability in managing complex stateful applications.


In the BLoC pattern, business logic is encapsulated within separate BLoC
classes, which act as intermediaries between UI components and data sources. BLoC classes
receive events from the UI, process them, update the application state, and emit new states
to notify UI components of changes.


The key components of the BLoC pattern in Flutter include:

  • Events: Represent user actions or system events that trigger state changes.
  • BLoC: Business Logic Component that contains the application’s business logic and
    manages state.
  • States: Represent different states of the application, which are emitted by the BLoC
    in response to events.
  • UI Components: Widgets that display the application’s state and respond to user
    interactions.

To implement the BLoC pattern in Flutter, you typically define BLoC
classes to manage state, create events and states to represent user actions and application
states, use StreamControllers or Cubits to handle state changes, and integrate BLoCs with UI
components using StreamBuilder or BlocBuilder widgets.


The benefits of using the BLoC pattern in Flutter include separation of
concerns, improved code organization and maintainability, reusability of business logic
across multiple UI components, testability with unit tests and widget tests, and scalability
for managing complex stateful applications.

While Provider and Riverpod are alternative state management solutions
in Flutter, the BLoC pattern offers a more structured and formal approach to managing state,
particularly for large-scale applications with complex state requirements. BLoC provides
better separation of concerns and facilitates better code organization compared to other
solutions.


Common use cases for using the BLoC pattern in Flutter applications
include managing form state, handling user authentication and authorization, fetching and
caching data from APIs, implementing complex user interfaces with dynamic behavior, and
coordinating interactions between multiple screens or components.


While the BLoC pattern offers many advantages, it can introduce some
complexity, especially for beginners. Setting up BLoC architecture and managing streams can
require a learning curve. Additionally, boilerplate code and increased file count may be a
concern for smaller projects.


Developers can find tutorials and resources for learning about the BLoC
pattern in Flutter on official Flutter documentation, community forums like Stack Overflow
and GitHub, developer blogs and tutorials, online courses and certifications, and Flutter
conferences and meetups. Additionally, exploring sample projects and GitHub repositories can
provide hands-on experience and insights into best practices.


Best practices for using the BLoC pattern effectively in Flutter
applications include keeping BLoC classes focused on specific domains or features,
minimizing dependencies between BLoC classes, using dependency injection for managing BLoC
instances, naming conventions for events and states, and writing comprehensive unit tests to
ensure correctness and reliability.