This repository is for understanding the core concepts of BLoC pattern in flutter.
BLoC – Udemy
This tutorial video is also available on youtube. If you want, then instead of buying the Udemy tutorial, you can follow the youtube tutorial. The full documentation on BLoC package is available in bloclibrary.dev.
Bloc was designed with three core values in mind:
1. Simple: Easy to understand & can be used by developers with
varying skill levels.
2. Powerful: Help make amazing, complex applications by composing
them of smaller components.
3. Testable: Easily test every aspect of an application so that we
can iterate with confidence.
Overall, Bloc attempts to make state changes predictable by regulating when a state change can occur and enforcing a single way to change state throughout an entire application.
BLoC Core Concept
1. Stream:
It is the foundation of BLoC. The stream is a river , which transport some data, on a boat, from the sender to the receiver. The transported data is asynchronous.
2. Cubit:
A cubit is the minimal version of a BLoC. BLoC actually extends cubit.
3. Bloc:
BLoC is the big brain of the project. Where as cubit is used to optimize the functionality of the project.
**Note: Start with a cubit. If you see the necessity, then modify your cubit into BLoC.
Flutter BLoC Concept
Some vital Flutter concepts to get going (widget, widget tree). 1. BlocProvider + CounterApp implementation. 2. BlocBuilder + CounterApp implementation. 3. BlocListener + CounterApp implementation. 4. BlocConsumer + CounterApp implementation. 5. RepositoryProvider 6. MultiBlocListener, MultiBlocProvider, MultiRepositoryProvider
RepositoryProvider
is a class. Which has the main function which makes flutter communicate with outer data layer i.e. internet, APIs, databases, etc.
BlocBuilder & BlocListener can be combined together to from BlocConsumer
BLoC Architecture
BLoC follows a specific folder pattern. The “Business logic” layer is separated from the “Presentation” layer and from the “Data” layer.
1. First design the models. A model is a blueprint
of the data an application will work with.
2. Next the data providers. The data providers’ responsibility is to provide raw data to it’s successor, which is the repositories
. It is actually an API
for our own application.
3. The repository is mainly a wrapper
around one, or more data providers. Repositories are also classes
, which contains dependencies of the respective data providers.
BLoC Testing
A test is defined by how we programmatically tell flutter to double check
the output given by a feature is equal to the expected response we planned on receiving. Packages needed for testing a BLoC:
dependencies:
flutter:
sdk: flutter
# Helpful for testing equal instances
equatable: ^2.0.3
# For testing
bloc_test: ^9.0.3
In Dart language, TWO INSTANCES of the same exact class are not equal even though they are basically identical. This is because, these two instances are stored in different part of the memory, and dart compares their location in memories instead of their value.
Hence, we need equatable
package to solve this problem. Equatable package simply @overrides
the equal operator.
CounterState stateA = CounterState(counterValue:0);
CounterState stateB = CounterState(counterValue:0);
statA != stateB
BLoC Access
BlocProvider() vs BlocProvider.value()
- BlocProvider() -> Necessary when transferring state to the HomeScreen()
- BlocProvider.value() -> Necessary for transferring state to the SecondScreen() & also
to the ThirdScreen()
- Local Access: Providing an instance of bloc/cubit to a
SINGLE SCREEN
is called local access. Example: wrapping theHomeScreen()
with BlocProvider(). - Route Access: Providing an instance of bloc/cubit to
MULTIPLE SCREEN
is called route access. Example: wrapping theSecondScreen()
&ThirdScreen()
with BlocProvider.value(). - Global Access: Providing am instance of bloc/cubit to
EVERY SCREEN
to your application. Example: wrapping theMaterialApp()
withBlocProvider()
orMultiBlocProvider()
.
Three types of routing option in Flutter:
- Anonymous routing: Navigation WITHOUT a RouteName.
- Named routing: Navigation WITH a RouteName. Recommended for small & medium size project.
- Generated routing: Separating the route information into a separate file. Recommended for large size project.
BLoC Communication
A Bloc/Cubit can communicate with each other using StreamSubscription
or BlocListener
. Both methods are equally good with their specific PROS/CONS
PROS of StreamSubscription
:
- organized, structured, easy to read & maintain.
- will help us practice stream skills.
CONS of StreamSubscription
:
- it may get cluttered really fast on huge apps
- not closing streamSubscription => huge memory leaks
———————————————– xxxx ———————————————–
BlocListener
is a widget, hence it should be inside the widget tree. This just notifies the bloc/cubit. It tells the bloc/cubit what to do, not how to do it.
PROS of BlocListener
:
- It takes care internally of all STREAMSubscriptions
- No need to take care of stream/memory leaks anymore
CONS of BlocListener
:
- The UI may get cluttered & hard to read with multiple BlocListener
BuildContext In-Depth
The BuildContext
is a tool which helps handle the location of the widget inside the widget tree. That means every widget is build within a BuildContext.
One of the most common ERROR of bloc/cubit is:
"BlocProvider.of() fails to find
a context containing a specific
bloc/cubit"
A BuildContext of a widget keeps tract only of their direct parent
and nothing else. Hence, the relationship between the BuildContext is a bottom-up relationship.
Fow of the BLoC contexts
introduced in bloc: ^6.1.0:
- context.watch()
- context.select()
- context.read()
Hydrated BLoC
Hydrated BLoC is used mainly for storing the state of a bloc/cubit. hydrated_bloc
exports a Storage
interface which means it can work with any storage provider. Out of the box, it comes with its own implementation: HydratedStorage
.
HydratedStorage
is built on top of HIVE for a platform-agnostic, performant storage layer. See the complete example for more details.
Packages necessary for using hydrated bloc are:
# For storing state into the device
hydrated_bloc: ^8.1.0
# For retrieving path for data storage
path_provider: ^2.0.11
BLoC Debugging
App Screenshots
</table
GitHub
#Flutter #bloc_concept #BLoc_Pattern