BLoC stands for Business Logic Components; it aims to separate the application’s business logic from User Interface, making the application code more unambiguous, scalable, and testable.
Before moving forward in the flutter bloc tutorial, let’s examine some of the pros and cons of the bloc design pattern.
Pros of Using BLoC
Cons of Using BLoC
We will build a relatively simple application to demonstrate how the BLoC uses streams to manage states and write some tests for the bloc.
We will build a text change application; press text will get changed and displayed with each button. You can refer below GIF for the same.
1. 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).
2. Make sure to match your pubspec.yaml file with mine to avoid any issues.
Want to have easy and hustle-free Flutter application development?
Bacancy is here for you! Contact us to hire Flutter developer to fulfill your project requirements efficiently with commendable problem-solving skills.
Let the game begin.
To understand how bloc works, we need to know what are events and states.
Bloc manages these events and states, i.e., it takes a stream of Events and transforms them into a stream of States as output.
@immutable abstract class AppBlocEvent { const AppBlocEvent(); } @immutable class ChangeTextEvent extends AppBlocEvent { const ChangeTextEvent();}
Moving forward in the flutter bloc tutorial. Here we have created a ChangeTextEvent, which will be fired when a button is clicked.
We have an abstract AppBlocEvent class because Bloc expects a single event to be added to the stream. Still, as there can be multiple events in an app, we create an abstract class and extend it whenever we want to create any new event for handling and passing multiple events to the bloc.
@immutable class AppState extends Equatable { final int index; final String text; const AppState.empty() : index = 0, text = 'Initial Text'; const AppState({ required this.index, required this.text, }); @override List
Similarly, we can create different states here in this app. We do not have many states. Therefore, we have created a single state to manage the app; however, we can create multiple states similar to events by creating an abstract appstate and extending it to our custom states.
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 part that contains the business logic of our application.
Put the pieces together.
Till now, events, states, bloc, and our application’s UI are not connected in any way. Let’s start piecing them together.
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 TextController( text: state.text, ); }, ), ), ), ); } }
Explanation: App.dart
BlocProvider(…): we use it to provide an instance of our bloc by placing it just below the root of the application so that it is accessible throughout it.
BlocConsumer(…): It is the area where everything happens.
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 ) )
Here we have added ChangetTextEvent onto the event stream, thereby triggering state change which causes the rebuild of the builder() in BlocConsumer, and changed text is displayed up on the screen.
There you have it!! With separated UI and business logic, you can change the UI code and just plug the Bloc in. It will work the same.
For testing the bloc, you require two packages:
Simply inside the test folder, create the app_bloc_test.dart file and start writing test.
Inside we are going to test two conditions:
There you go!!😊😊
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
Feel free to clone the repository: flutter-bloc-demo and start experimenting with the code.
The Flutter BLoC tutorial was helpful for you to get started with state management using the BLoC pattern. We will be back with another Flutter tutorial; till then, visit the Flutter tutorials page and learn more about Flutter concepts. Let us know if you want any specific topics to be covered. Write us back your suggestions and feedback. Happy Coding!
Navigating client's requirement with precision is what our developers' focuses on. Besides, we develop to innovate and deliver the best solutions to our clients.
get in touchYour Success Is Guaranteed !
We accelerate the release of digital product and guaranteed their success
We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.