Implementing BLoC Pattern for parsing JSON from API
Developers should follow a state management procedure. A pattern makes the project scalable, readable and and maintainable. So far, lots of pattern available for managing state in Flutter. Here we are going to see the implementation of BLoC pattern. BLoC pattern is a design pattern for separating business logic from UI layer. Fortunately there is a package available for simplifying the process of implementing BLoC pattern, which is flutter_bloc. I am going to fetch data from this API. So let’s get started!
Project Overview: Our app will have 2 screens. Homescreen will have a list of articles, upon click on the list item, user will be navigated to the second screen. Second screen will contain the details of the article.
BLoC overview: Lets have a brief overview of the flutter_bloc package. A BLoC takes stream of events as inputs and converts them into stream of states as outputs. This package abstracts the reactive aspects of the BLoC pattern. Lets have a quick view on some important terms.
EVENTS: Input to a BLoC is known as event. These are actions on screen, such as button click.
STATES: States are the output of Bloc. In BLoC pattern, user interface(UI) is changed based on the stream of received states.
So now, lets start coding…
First, let’s add flutter_bloc package in pubspec.yaml file. Additionally lets add equatable package, which is for comparing value equality of objects.
dependencies:
flutter:
sdk: flutter
http: ^0.12.0
flutter_bloc: ^2.0.0
equatable: ^0.6.1
PROJECT STRUCTURE
We’ll have following folders inside lib folder.
- res
- data
- bloc
- ui
Inside ‘res’ folder, we’ll put constant values like strings, colors, arrays etc. For now, lets put the url in strings.dart file.
Inside data folder, we’ll have a models folder and repositories folder. Lets create api_result_model.dart file inside model folder. We’ll use this tool for converting json to dart object. So let’s put converted model class inside api_result_model.dart file.
Now, inside repository folder, create article_repository.dart file. Here we gonna parse the json and convert them into our desired model.
Here inside getArticles()
method, we are converting json reponse into a list a of ‘Articles’ object. Now, our ‘data’ folder is completely ready.
Now, let’s move on to the core of this article, BLoC.
In this particular app, we need only a single BLoC, which is for fetching articles from API and showing them in a ListView
. So now create article_bloc folder inside blocs folder. Let’s create three files inside article_bloc folder : article_event.dart, article_state.dart and article_bloc.dart.
Events: In this app we have a single event which is fetching articles. We gonna create abstract classes both for the events and states, and then respective events and states gonna extend those abstract classes. Here is the abstract event class with the single event :
States: Now think about the states of the app. Parsing the articles will definitely take some times. So initially there will be a loading indicator. And then articles may be fetched successfully or some errors may interrupt. So two more states for success and errors. Additionally another state need to be added for initial moment. So we will have 4 states :
ArticleInitialState
ArticleLoadingState
ArticleLoadedState
ArticleErrorState
So now, let’s create an abstract class for state and extend that abstract class by the 4 state classes of our app.
If parsing goes successful, ArticleLoadedState
will handle a list of Articles, and if error occurs, ArticleErrorState
will show an error message. That’s why the classes have List<Articles>
and a String
field respectively.
Now come to the article_bloc file. Here we have created our bloc which extends the Bloc class. We need to mention the event and state as type parameter. Also we need to override the initialState
and mapEventToState
methods. initialState
is called even before any event has been processed. We are returning ArticleInitialState
from initialState
method.
mapEventToState
is a must to implement. It takes events as stream and converts them into states as streams which are consumed by presentation layer. mapEventToState
is called whenever an event is added by presentation layer.
Here in this case, initially when the event is added, ArticleLoadingState
is yielded. After fetching articles successfully, ArticleLoadedState
is yielded. If error occurs, then ArticleErrorState
will be yielded. So now bloc part of our app is ready!
Now time to complete the presentation layer.
main.dart: We are going to use the BlocProvider
widget from flutter_bloc package in order to make the instance of ArticleBloc
available to the entire subtree.
BlocProvider
is used to build ArticleBloc
which is now available to the rest of the subtree. BlocProvider
will automatically close the ArticleBloc
, so we don’t need to use a StatefulWidget
. But our Homepage
is instead a StatefulWidget
. Reason is, there is no user action initially when the api gets called. So, we need to call bloc from initState()
.
home_page.dart:
Inside the build()
method of Homepage
widget, we are using BlocBuilder
widget with ArticleBloc
and ArticleState
as type parameter. BlocBuilder
takes an optional ‘bloc’ parameter. But as we’ve specified the type of the bloc and the type of the state, BlocBuilder
will find the bloc. So we dont need to use ‘bloc’ parameter. Inside builder parameter, we are checking state and returning appropriate UI based on the state.
ONE LAST THING…
Additionally we can use the BlocListener
widget. BlocListener
is a widget where we can trace logs, show snackbars etc. One time actions can be performed inside BlocListener
. So now, lets wrap BlocBuilder
with BlocListener
to show a snackbar on ArticleErrorState
. Additionally, a ‘refresh’ icon is added on AppBar where onTap()
call the event again. So our final build()
will look like this :
Now, the only remaining task is — adding the event to the ArticleBloc
. For that, we gonna have an instance of ArticleBloc
. We’ll initialize it and add event to it inside initState()
method :
So that’s all! Business logic is now separated from the presentation layer.
Full source code here : https://github.com/newajthevillager/Flutter-Json-Parsing-with-BLoC
Full explanation in Youtube : https://www.youtube.com/watch?v=27EP04T824Y&t=9s