For me when I started learning bloc and cubit , experience was very scary because people(me) tend to directly jump into implementations.
One very unusual thing happened with me and many fellow developers is we directly get all the implemented steps in some GitHub project or we get the same old counter example to understand Cubit/Bloc
In this post we will be following along how to start implementing cubit with step by step approach . I will be showcasing here a very detailed guide on how to approach each class and how to think along when implementing cubit. In this post we will not be dumping all the source code at once , instead we will cover each class creation and also see where its significant and why we are creating it. At some places we will be coming with widget codes directly because we have very simple UI to explain the bloc.cubit concepts.
Why Bloc is important ?
Very simple: To separate business logic and UI code. And for accessing the state/data of one widget into some another widgets.(Global State management)
So Global state management is nothing but accessing the data generated in one widget into another widget which is created deep inside app widget hierarchy. E.g Marking a list of items and move to cart, so the items that are added in the cart is usable by not only cart screen but at many other places. In our example we will be fetching data using Cubit in this part -1.
Let’s see the diagram and break into this diagram.
We will create all these three parts in our code step by step and finally connect all this in the main.dart using provider.
Very important is “functions” because our app UI will change using function call in Cubit.
One important difference between Cubit and Bloc is :
Cubit works with “functions” and Bloc works with “Events”
So enough of theory , lets start with creating this components
Step 1: Lets create a UI screen first, our UI screen is movie_page.dart which is a first home page which will be loaded in main.dart.
movie_page.dart contains a statefulwidget which consists of simple list builder:
https://github.com/raviyadav5951/CubitExample/blob/main/lib/ui/movie_page.dart
Let’s install these dependencies:
bloc: ^8.1.3
flutter_bloc: ^8.1.4
dio: ^5.4.1
equatable: ^2.0.5
Dio we will be using for api call and equatable we will be using to compare the cubit classes.
We need bloc extension by Felix Angelov in vscode for making our life easy , these extension will provide a superpower to vscode for creating cubit class and provide us autogenerated templates for creating cubit classes, so that we dont need to write boilerplate codes.
https://marketplace.visualstudio.com/items?itemName=FelixAngelov.bloc
Now , after adding this extension we will be creating our cubit class , these will look something like this. You have to right click on folder and selection “new cubit option”
https://miro.medium.com/v2/resize:fit:1400/format:webp/1*o9i8kt5Dgs3MIwwGtdVqWg.png
These will create two important classes. One is Cubit class and second is state class.
We know that any api integration will move step by step from three/four states. Initial state, Loading state, Loaded state(Success state) and Error State(Fail State). We will create a function which will reflect these states so that our app can gradually covers all these states and our UI changes gets reflected accordingly
part of 'movie_cubit.dart';
abstract class MovieState extends Equatable {}
class InitialState extends MovieState {
@override
List<Object?> get props => [];
}
class LoadingState extends MovieState {
@override
List<Object?> get props => [];
}
class LoadedState extends MovieState {
LoadedState(this.movies);
final List<Results> movies;
@override
List<Object> get props => [movies];
}
class ErrorState extends MovieState {
@override
List<Object> get props => [];
}
We have different states , we are returning List<Result> which is a list of movies which will be returned on success state, empty on Loading state, empty on error state.
Based on this states our app UI will react , on loading our app will show loader and on success it will render the list , these we will see at the end.
And our Cubit class looks like these, we will cover repository class also, these is the same class(third component) from cubit diagram. so till here we have covered all the classes
import ‘package:movies_cubit/repository/movie_repository.dart’;
part ‘movie_state.dart’;
class MovieCubit extends Cubit<MovieState> {
MovieCubit({required this.repository}) : super(InitialState());
final MovieRepository repository;
void getTrendingMovies() async {
try {
emit(LoadingState());
final movies = await repository.getMovies();
emit(LoadedState(movies));
} catch (e) {
emit(ErrorState());
}
}
}
From the stateful widget that we have created , we will be calling getTrendingMovies() function and in the function above you can see “emit” keyword. This emit will be a state that we want our app UI should act on. You have observed that in the MovieCubit constructor we have passed InitialState.
Basically emit tells the UI to update the UI state . E.g emit(LoadingState()) tells user that UI is in loading state so , show your loading indicator and when your data arrived successfully then show the list of movies. And on error show the UI which shows some error messsage.
Now comes BlocBuilder, this is the widget like ListView.builder, but this widgets accets cubit and state that we have created , so this is a kind of integration step which is made in the final UI. And our Movie List widget will look like this
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:movies_cubit/cubit/cubit/movie_cubit.dart';
class MoviePage extends StatefulWidget {
const MoviePage({super.key});
@override
State<MoviePage> createState() => _MoviePageState();
}
class _MoviePageState extends State<MoviePage> {
@override
void initState() {
context.read<MovieCubit>().getTrendingMovies();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Movies List',
),
),
body: BlocBuilder<MovieCubit, MovieState>(builder: (context, state) {
if (state is LoadingState) {
return const Center(
child: CircularProgressIndicator.adaptive(),
);
} else if (state is ErrorState) {
return const Center(
child: Icon(Icons.close),
);
} else if (state is LoadedState) {
final movies = state.movies;
return ListView.builder(
itemCount: movies.length,
itemBuilder: (context, index) => Card(
child: ListTile(
title: Text(movies[index].title ?? ''),
leading: CircleAvatar(
backgroundImage: NetworkImage(
"https://image.tmdb.org/t/p/w500${movies[index].posterPath}"),
),
),
),
);
} else {
return const SizedBox.shrink();
}
}),
);
}
}
We are conditinally showing progress indicator when app is in loading state, showing list of movies when app is in success state. We have connected our Cubit +State+UI, but wait final step is still not completed. We have to provide the Cubit and Repository(api call ) class at the beginning so that complete app can use the Repository and Cubit class, we will be using BlocProvider
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: BlocProvider<MovieCubit>(
create: (context) => MovieCubit(
repository: MovieRepository(
Dio(),
),
),
child: const MoviePage(),
),
);
}
}
If you have multiple cubit then you have to include all cubits here, you have to use MultiBlocProvider widget in that case.
https://github.com/raviyadav5951/CubitExample/blob/main/screen_record_cubit.mov
Complete example source code can be found here:
https://github.com/raviyadav5951/CubitExample
I hope you get to learn cubit from this blog post, do give a clap on this post. Aplogies for any mistake and I am open to feedback. Do connect with me on social handles.
Ravi Yadav is an Android developer whose passion is to develop Android applications and sharing his work. He loves to post the tutorials which he created while learning any new latest technology topic.He loves to share about the latest technology happenings and other tricks that will be helpful for readers of Askfortricks.
Feeling glad to receive your comment