Cubit and Bloc simple example

ref –

  • https://resocoder.com/2020/08/04/flutter-bloc-cubit-tutorial/
  • https://medium.com/flutterando/cubit-a-simple-solution-for-app-state-management-in-flutter-66ab5279ef73
  • http://chineseruleof8.com/code/index.php/2021/04/14/beginning-bloc-for-flutter/
  • http://chineseruleof8.com/code/index.php/2021/04/15/working-with-flutter-bloc/
  • https://github.com/irvine5k/cubit_movies_app/

A Cubit is the base for Bloc (in other words Bloc extends Cubit).

Cubit is a special type of Stream which can be extended to manage any type of state .

A functions is generally that something you create to do some orders as you want and this function will be achieved my orders when I would CALLING IT so it can’t achieve anything without any call from me . something like when I call KFC to order some food the function here is calling the restaurant to order my food because the restaurant can’t order food to me without calling it.

It replaces events in the bloc architecture. Originally, UI actions create events. Events get mapped to State. And we return certain state to update the data to be drawn in the UI.

However, instead of mutating individual fields, we emit whole new MyState objects. Also, the state is in a class separate from the one responsible for changing the state.

Importing Cubic

pubspec.yaml

State

A rule of thumb is to always build out the state class(es) first. So, what kind of WeatherState do we want to have?

We have the abstract class WeatherState to denote top of hierarchy.

We then create different Weather States that implements this abstraction. In our case:

WeatherInitial – This WeatherInitial state will indicate that no action has yet been taken by the user and that we should display an initial UI
WeatherLoading – we are waiting for the weather to arrive from its web api
WeatherLoaded – the data has arrived!
WeatherError – internet connection broke somehow.

We also override annotation operator ==. This is because UI updates when state are different. Flutter will do a comparison between different states. If the states are different, update the UI. If they are the same, don’t do anything. Thus, for our Weather state, we need to override this to let flutter do the comparison.

If the two states are identical, then UI won’t do anything.
If the incoming object is of the same state (say WeatherLoaded) and the state’s weather object is the same, then we return true and UI won’t update.

But if either:
– the Object o is of another state
– the weather has changed

then we return false, to let Flutter know that the state have changed.

Always override equality of the state classes. Bloc will not emit two states which are equal after one another.

Thus, if we do not override equality, Bloc will ALWAYS update the UI and it degrades performance.

Cubit

Having finished our work on the state, let’s implement the WeatherCubit that will perform logic such as getting the weather from the WeatherRepository and emit states.

So we extend from Cubit

We ctrl + click Cubit to see what’s going on underneath. We see that it’s an abstract class that uses a StreamController. This is mentioned in our earlier tutorials on basic blocs and stream:

  • http://chineseruleof8.com/code/index.php/2021/04/14/beginning-bloc-for-flutter/
  • http://chineseruleof8.com/code/index.php/2021/04/15/working-with-flutter-bloc/

A stream can only take one type, and we see that Cubit takes on the state that we specify in the type bracket.
The StreamController instance then broadcasts it and it will be sink.add, or stream.listen accordingly. But when using Cubic, all that details are hidden away.

Do take note of the constructor. It takes a state as parameter.

Hence that is why in our initialization code, we put WeatherInitial() instance because it assigns the initial state to Cubit.

We then have our a weatherRepository instance that gets the data from a web api.

Notice that we don’t need to override mapEventToState here like we do in bloc architecture.
That is because in Cubit, there is no events. We only have functions that trigger state change.

Hence, in our case, we call getWeather to asynchronously get data. But before it does, we first emit a WeatherLoading state instance. This state is to trigger a circular indicator in our UI, as will be shown later.

Then we do the async operation and get the weather data. After receiving this data, we emit that state to be loaded, along with the weather data itself.

The states then get reflected on the UI through BlocBuilder:

weather_search_page.dart

Running the App

In the very beginning, we have this:

It’s a class that extends StatefulWidget. We need to override StatefulWidget’s abstract method createState. createState returns State. Thus, we need to create a class that extends from State. We name it WeatherSearchPageState. The type of State is WeatherSearchPage.

We then override the build function, which is used to build the UI.

When we run the app, we get the log messages like so:


flutter: weather_search_page.dart – WeatherSearchPage – createState
flutter: weather_search_page.dart – state: Instance of ‘WeatherInitial’
flutter: weather_search_page.dart – WeatherInitial state –> returning buildInitialInput() UI

We get WeatherInitial state because in WeatherCubit, we initialized state it WeatherInitial():

The way how the UI is implemented is. Our UI is organized in such a way that whenever a state is such, we return the proper UI widgets.

Then when we put in a city for weather, we start at the cubit. It uses the weather repo to do its async operation. Once its done, it emits a state. This state then is caught in the UI where weather_search_page.ldart sees that its a WeatherLoading.


flutter: weather_cubit.dart – weather is loading…
flutter: weather_repository.dart – getting weather for shanghai
flutter: weather_search_page.dart – state: Instance of ‘WeatherLoading’
flutter: weather_search_page.dart – WeatherLoading state –> returning buildLoading() UI

Then few seconds later, in weather_cubit, we receive weather data. It will emit WeatherLoaded.
Now, Cubit will do a comparison between WeatherLoading and WeatherLoaded in its operator overloaded ==.


flutter: weather_cubit.dart – received weather data!
flutter: weather_state.dart – WeatherLoaded – comparing Instance of ‘WeatherLoading’ and Instance of ‘WeatherLoaded’
flutter: weather_state.dart – DIFFERENT state, update UI NOW!

When the states are different, we update UI.


flutter: weather_search_page.dart – state: Instance of ‘WeatherLoaded’
flutter: weather_search_page.dart – WeatherLoaded state –> returning buildColumnWithData() UI