Flutter in a Weekend: Saturday — View Creation and HTTP Calls

Previously we installed Flutter elements in our system and created our first application with it. Afterwards, we run the application on Android and iOS. Now it is time to write some code!

Flutter uses Dart language for development. Dart is a general-purpose programming language developed by Google. We will use this language to create our views and functional parts.

If you are ready, let’s start with the second part of the Flutter adventure.

Creating a List with Cards

As stated in the previous blog post, we will be creating a movie application which shows the top-rated movies from TMDb database.

Let’s start by deleting everything in the main.dart file and create the famous “Hello World” application together to have some information about basics of the view hierarchy in Flutter.

Before we proceed with code, I want to tell you about views in Flutter. Each view element in Flutter is called widgets. Widgets describe what their view should look like given their current configuration and state. A widget’s main job is to implement a build function, which describes the widget in terms of other, lower-level widgets. When writing an app, you’ll commonly author new widgets that are subclasses of either StatelessWidget or StatefulWidget, depending on whether your widget manages any state. When a widget’s state changes, the widget rebuilds its description, which the framework diffs against the previous description in order to determine the minimal changes needed in the underlying render tree to transition from one state to the next. That will be enough for now.

In Dart, execution starts from main() method. Therefore we will be starting with implementing that.

void main() {
// To be implemented
}

As you see, right now it is empty. We should start by adding a method called runApp. This method is the method to inflate the given widget and attach it to the screen. Flutter provides you plenty of widgets which you can check out at widgets catalog page. During this tutorial, we will be using material widgets.

For creating our views we will be using Scaffold class. This class helps us to implement the basic material design visual layout structure like app bar, bottom navigation drawer etc. To be able to use material design components, of course, we would wrap this scaffold class with MaterialApp class.

Alignments in flutter mostly handled either byAlign class or some special classes (e.g.Center :a specialised version of Align class).

// Main method starts execution
void main() {
runApp(
new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Movie List Application'),
),
body: new Center(
child: new Text("Hello World"),
),
)
)
);
}

Since we have an understanding of widgets and views in Flutter, we can continue with our main objective, creating a list of movie items.

Let’s continue by making an HTTP call to our API.

How to make an HTTP Call?

Native way of doing an HTTP call in Flutter is to create an HTTP client and make the request by passing the URL to it.

Since this operations can take long time depending on our internet speed, it is better to do it as an asynchronous operation. For making a method asynchronous, all you have to do in Flutter is to add async keyword to the end of the method.

getMovies() async {
//Get movies
}

One another thing to mention during an async operation is await keyword. Since programming languages are keep compiling with the next line after running the current line, we need to be sure to keep our code is on hold, while an operation is happening. And this keyword is helping us in that matter. It holds the code operation until the current operation finishes.

getMovies() async {
final String url = 'http://api.themoviedb.org/3/movie/top_rated?api_key=<your-api-key-here>';
var httpClient = new HttpClient();
try {
// Make the call
var request = await httpClient.getUrl(Uri.parse(url));
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var json = await response.transform(UTF8.decoder).join();
// Decode the json response
var data = JSON.decode(json);
// Get the result list
List results = data["results"];
// Print the results.
print(results);
} else {
print("Failed http call.");
}
} catch (exception) {
print(exception.toString());
}
}

If you call the getMovies() method in your main method, then in the log you can see the movie list is written.

Movie call result at bottom.

Now let’s hook this information to a Movie model and bind it to our view.

class Movie {

String title;
String posterPath;
String backdropPath;
String originalTitle;
double voteAverage;
String overview;
String releaseDate;

Movie(this.title,
this.posterPath,
this.backdropPath,
this.originalTitle,
this.voteAverage,
this.overview,
this.releaseDate);
}

Now we have our Movie object. If you check the call, you can see that, there are some other information can be used by developers too but, I think for our application it makes sense to have only these. Let’s create a method to create a list of movies.

/// Method to parse information from the retrieved data
List<Movie> createMovieList(List data) {
List<Movie> list = new List();
for (int i = 0; i < data.length; i++) {
String title = data[i]["title"];
String posterPath = data[i]["poster_path"];
String backdropImage = data[i]["backdrop_path"];
String originalTitle = data[i]["original_title"];
double voteAverage = data[i]["vote_average"];
String overview = data[i]["overview"];
String releaseDate = data[i]["release_date"];

Movie movie = new Movie(
title,
posterPath,
backdropImage,
originalTitle,
voteAverage,
overview,
releaseDate);
list.add(movie);
}
return list;
}

In this method, we are passing the result data from the server to the method and iterate through it to create result Movie objects.

If we run our project now, at the printed result part, we can see movie objects instead of the strings that we have before. We need to modify our code as stated below.

getMovies() async {
...
List results = data["results"];
// Get the Movie list
List<Movie> movieList = createMovieList(results);
// Print the results.
print(movieList);
...
}
Movie instances result

Next step is to see the results in the real device instead of log. Before we continue on that, we will talk about one more concept, which is called Future. A future is used to represent a potential value, or error,
that will be available at some time in the future. Receivers of a future can register callbacks that handle the value or error once it is available.

Meanwhile using future, we can also use a class called FutureBuilder to create a widget that builds itself based on the latest snapshot of interaction with a future. So we can use this approach to show a progress circle meanwhile an operation happens.

The first step is to update the getMovies() lines as below according to the new information that we have learned.

/// Method to get movies from the backend
Future<List<Movie>> getMovies() async {
...
List<Movie> movieList = createMovieList(results);
// Print the results.
return movieList;
...
} catch (exception) {
print(exception.toString());
}
return null;
}

The second step is to create a view with the information that we retrieve. Let’s update the body part of our main method as follows.

void main() {
runApp(
new MaterialApp(
...
// Body part of the screen
body: new FutureBuilder(
future: getMovies(),
builder: (BuildContext context,
AsyncSnapshot<List> snapshot) {
if (!snapshot.hasData)
// Shows progress indicator until the data is load.
return new MaterialApp(
home: new Scaffold(
body: new Center(
child: new CircularProgressIndicator(),
),
)
);
// Shows the real data with the data retrieved.
List movies = snapshot.data;
return new CustomScrollView(
primary: false,
slivers: <Widget>[
new SliverPadding(
padding: const EdgeInsets.all(10.0),
sliver: new SliverGrid.count(
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
crossAxisCount: 2,
children: createMovieCardItem(movies, context),
),
),
],
);
}
)
...
}

Let’s analyse the code above. We have talked earlier about FutureBuilder. It also has a future attribute. In this future attribute, we will call our getMovies method. In the builder attribute, we have a context and information snapshot. If the information snapshot is empty, we will show progress indicator, if it is not empty we will show the information.

The part which shows the information, in that part for the root element we are using CustomScrollView.It is a widget that creates custom scroll effects using slivers (children). We will use also SliverGrid for having the grid view that we wanted. But still, we have an error at the createMovieCardItem method. Because we did not create it yet.

List<Widget> createMovieCardItem(List<Movie> movies, BuildContext context) {
// Children list for the list.
List<Widget> listElementWidgetList = new List<Widget>();
if (movies != null) {
var lengthOfList = movies.length;
for (int i = 0; i < lengthOfList; i++) {
Movie movie = movies[i];
// Image URL
var imageURL = "https://image.tmdb.org/t/p/w500/" + movie.posterPath;
// List item created with an image of the poster
var listItem = new GridTile(
footer: new GridTileBar(
backgroundColor: Colors.black45,
title: new Text(movie.title),
),
child: new GestureDetector(
onTap: () {
///TODO: Add detail page behaviour. Will be added in the next blog post.
},
child: new Image.network(imageURL, fit: BoxFit.cover),
)
);
listElementWidgetList.add(listItem);
}
}
return listElementWidgetList;
}

We create our list items via, GridTile widget. Add a footer to it for showing the title of the movie at the bottom.

It is easy to get images in the flutter. We can directly use network method from Image class. It will retrieve the image and fit it according to our need. We will crop it to the center now.

Now we are all set. If you run your application, you will see a list of movie elements.

Screenshots

Conclusion

We have learnt a lot of new stuff today. But with the information that we have learnt, we created something really cool for both platforms by writing code only once. This is the biggest advantage of Flutter. Now it is time for you to relax and wait for this information to settle. Tomorrow we will add detail page and do some cleanup in our code.

Looking forward to it.

p.s. You can find the Github project link below in the FPM-Saturday branch.