Hope this small Q&A section cleared some of your doubts. If you need further clarity or want to ask a specific question, you can comment down below or connect directly with me at LinkedIn.

Let’s start building the project with BLOC pattern

1. First create a new project and clear all the code in the main.dart file. Type below command in your terminal:

flutter create myProjectName

2. Write down the below code in your main.dart file:

import 'package:flutter/material.dart';

import 'src/app.dart';



void main(){

runApp(App());

}

You must be getting an error in the second line. We will solve it in the upcoming steps.

3. Create a src package under the lib package. Inside src package create a file and name it as app.dart. Copy paste the below code inside the app.dart file.

import 'package:flutter/material.dart';

import 'ui/movie_list.dart';



class App extends StatelessWidget {

@override

Widget build(BuildContext context) {

// TODO: implement build

return MaterialApp(

theme: ThemeData.dark(),

home: Scaffold(

body: MovieList(),

),

);

}

}

4. Create a new package inside the src package and name it as resources.

Now create few new packages i.e blocs, models, resources and ui as shown in the below diagram and then we are set with the skeleton of the project:

Project structure

blocs package will hold our BLOC implementation related files. models package will hold the POJO class or the model class of the JSON response we will be getting from the server. resources package will hold the repository class and the network call implemented class. ui package will hold our screens that will be visible to the user.

5. One last thing we have to add i.e RxDart a third party library. Open your pubspec.yaml file and add rxdart: ^0.18.0 as shown below:

dependencies:

flutter:

sdk: flutter



# The following adds the Cupertino Icons font to your application.

# Use with the CupertinoIcons class for iOS style icons.

cupertino_icons: ^0.1.2

rxdart: ^0.18.0

http: ^0.12.0+1

sync your project or type below command in terminal. Make sure you execute this command inside your project directory.

flutter packages get

6. Now we are complete with the skeleton of the project. Time to deal with the most bottom layer of the project i.e the network layer. Let’s understand the API end point which we are going to consume. Hit this link and you will be taken to the movie database API site. Sign up and get your API key from the Settings page. We will be hitting the below url to get the response:

http://api.themoviedb.org/3/movie/popular?api_key=“your_api_key”

Put your API key in the above link and hit(Remove double quotes as well). You can see the JSON response something like this:

{

"page": 1,

"total_results": 19772,

"total_pages": 989,

"results": [

{

"vote_count": 6503,

"id": 299536,

"video": false,

"vote_average": 8.3,

"title": "Avengers: Infinity War",

"popularity": 350.154,

"poster_path": "\/7WsyChQLEftFiDOVTGkv3hFpyyt.jpg",

"original_language": "en",

"original_title": "Avengers: Infinity War",

"genre_ids": [

12,

878,

14,

28

],

"backdrop_path": "\/bOGkgRGdhrBYJSLpXaxhXVstddV.jpg",

"adult": false,

"overview": "As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his goal is to collect all six Infinity Stones, artifacts of unimaginable power, and use them to inflict his twisted will on all of reality. Everything the Avengers have fought for has led up to this moment - the fate of Earth and existence itself has never been more uncertain.",

"release_date": "2018-04-25"

},

7. Let’s build a model or POJO class for this type of response. Create a new file inside the models package and name it as item_model.dart. Copy and paste the below code inside item_model.dart file:

class ItemModel {

int _page;

int _total_results;

int _total_pages;

List<_Result> _results = [];



ItemModel.fromJson(Map<String, dynamic> parsedJson) {

print(parsedJson['results'].length);

_page = parsedJson['page'];

_total_results = parsedJson['total_results'];

_total_pages = parsedJson['total_pages'];

List<_Result> temp = [];

for (int i = 0; i < parsedJson['results'].length; i++) {

_Result result = _Result(parsedJson['results'][i]);

temp.add(result);

}

_results = temp;

}



List<_Result> get results => _results;



int get total_pages => _total_pages;



int get total_results => _total_results;



int get page => _page;

}



class _Result {

int _vote_count;

int _id;

bool _video;

var _vote_average;

String _title;

double _popularity;

String _poster_path;

String _original_language;

String _original_title;

List<int> _genre_ids = [];

String _backdrop_path;

bool _adult;

String _overview;

String _release_date;



_Result(result) {

_vote_count = result['vote_count'];

_id = result['id'];

_video = result['video'];

_vote_average = result['vote_average'];

_title = result['title'];

_popularity = result['popularity'];

_poster_path = result['poster_path'];

_original_language = result['original_language'];

_original_title = result['original_title'];

for (int i = 0; i < result['genre_ids'].length; i++) {

_genre_ids.add(result['genre_ids'][i]);

}

_backdrop_path = result['backdrop_path'];

_adult = result['adult'];

_overview = result['overview'];

_release_date = result['release_date'];

}



String get release_date => _release_date;



String get overview => _overview;



bool get adult => _adult;



String get backdrop_path => _backdrop_path;



List<int> get genre_ids => _genre_ids;



String get original_title => _original_title;



String get original_language => _original_language;



String get poster_path => _poster_path;



double get popularity => _popularity;



String get title => _title;



double get vote_average => _vote_average;



bool get video => _video;



int get id => _id;



int get vote_count => _vote_count;

}

I hope you can map this file with the JSON response. If not, we are mostly interested in the poster_path inside the Results class that’s what you need to know to move further. We will display all the posters of popular movies in our main UI. fromJson() method is just getting the decoded JSON and putting the values in the correct variables.

8. Now its time to work on the network implementation. Create a file inside the resources package and name it as movie_api_provider.dart. Copy and paste the below code inside the file and I will explain it to you:

import 'dart:async';

import 'package:http/http.dart' show Client;

import 'dart:convert';

import '../models/item_model.dart';



class MovieApiProvider {

Client client = Client();

final _apiKey = 'your_api_key';



Future<ItemModel> fetchMovieList() async {

print("entered");

final response = await client

.get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey");

print(response.body.toString());

if (response.statusCode == 200) {

// If the call to the server was successful, parse the JSON

return ItemModel.fromJson(json.decode(response.body));

} else {

// If that call was not successful, throw an error.

throw Exception('Failed to load post');

}

}

}

Note: Please put your API key in the variable _apiKey inside the movie_api_provider.dart file or else it won’t work.

fetchMovieList() method is making the network call to the API. Once the network call is complete it’s returning a Future ItemModel object if the network call was successful or it will throw an Exception.

9. Next we are going to create a new file inside the resources package and name it as repository.dart. Copy and paste the below code inside the file:

import 'dart:async';

import 'movie_api_provider.dart';

import '../models/item_model.dart';



class Repository {

final moviesApiProvider = MovieApiProvider();



Future<ItemModel> fetchAllMovies() => moviesApiProvider.fetchMovieList();

}

We are importing the movie_api_provider.dart file and calling its fetchMovieList() method. This Repository class is the central point from where the data will flow to the BLOC.

10. Now comes a little complicated part. Implementing the bloc logic. Let’s create a new file inside the blocs package and name it as movies_bloc.dart. Copy paste below code and I will explain you the code in little detail:

import '../resources/repository.dart';

import 'package:rxdart/rxdart.dart';

import '../models/item_model.dart';



class MoviesBloc {

final _repository = Repository();

final _moviesFetcher = PublishSubject<ItemModel>();



Observable<ItemModel> get allMovies => _moviesFetcher.stream;



fetchAllMovies() async {

ItemModel itemModel = await _repository.fetchAllMovies();

_moviesFetcher.sink.add(itemModel);

}



dispose() {

_moviesFetcher.close();

}

}



final bloc = MoviesBloc();

We are importing a package import ‘package:rxdart/rxdart.dart’; which will eventually import all the RxDart related methods and classes in this file. Inside the MoviesBloc class, we are creating the Repository class object which will be used to access the fetchAllMovies() . We are creating a PublishSubject object whose responsibility is to add the data which it got from the server in the form of ItemModel object and pass it to the UI screen as a stream. To pass the ItemModel object as stream we have created another method allMovies() whose return type is Observable(watch this video if you don’t understand Observables). If you see the last line we are creating the bloc object. This way we are giving access to a single instance of the MoviesBloc class to the UI screen.

If you don’t know what reactive programming is. Please read this simple explanation. In simple words, whenever there is new data coming from the server. We have to update the UI screen. To make this updating task simple we are telling the UI screen to keep observing any change coming from the MoviesBloc class and accordingly update your content. This “observing” of new data can be done using RxDart.

11. Now the last section. Create a new file inside the ui package and name it as movie_list.dart. Copy paste the below code:

import 'package:flutter/material.dart';

import '../models/item_model.dart';

import '../blocs/movies_bloc.dart';



class MovieList extends StatelessWidget {

@override

Widget build(BuildContext context) {

bloc.fetchAllMovies();

return Scaffold(

appBar: AppBar(

title: Text('Popular Movies'),

),

body: StreamBuilder(

stream: bloc.allMovies,

builder: (context, AsyncSnapshot<ItemModel> snapshot) {

if (snapshot.hasData) {

return buildList(snapshot);

} else if (snapshot.hasError) {

return Text(snapshot.error.toString());

}

return Center(child: CircularProgressIndicator());

},

),

);

}



Widget buildList(AsyncSnapshot<ItemModel> snapshot) {

return GridView.builder(

itemCount: snapshot.data.results.length,

gridDelegate:

new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),

itemBuilder: (BuildContext context, int index) {

return Image.network(

'https://image.tmdb.org/t/p/w185${snapshot.data

.results[index].poster_path}',

fit: BoxFit.cover,

);

});

}

}

Best and interesting part of this class is, I am not using a StatefulWidget. But instead I am using a StreamBuilder which will do the same job what StatefulWidget does i.e updating the UI.

One thing to point here, that I am making a network call inside the build method which should not be done as build(context) a method can be called multiple times. I will be updating this article with a better approach. But for now, as the article is getting big and complicated I am keeping things simple i.e making the network call inside the build(context) method.

As I told you, our MoviesBloc class is passing the new data as a stream. So to deal with streams we have a nice inbuilt class i.e StreamBuilder which will listen to the incoming streams and update the UI accordingly. StreamBuilder is expecting a stream parameter where we are passing the MovieBloc’s allMovies() method as it is returning a stream. So the moment there is a stream of data coming, StreamBuilder will re-render the widget with the latest data. Here the snapshot data is holding the ItemModel object. Now you can you any Widget to display whatever is there in the object(Here your creativity comes into the picture). I used a GridView to display all the posters that are there in the results list of ItemModel object. This is the output of the final product:

Small demo. The video was not capturing the complete frames I guess 😐

So we have hit the end of this article. Great job folks for holding on till the end. Hope you like this article. If you have any doubts or questions do connect with me at LinkedIn or Twitter. Do appreciate the article with some claps and comments.

If you want the complete code. Here is the github repository of the project.

Check out my other articles