We have used Volley as networking library in lot of my articles. Today we are going to look at another awesome library Retrofit to make the http calls. Retrofit is denitely the better alternative to volley in terms of ease of use, performance, extensibility and other things. It is a type-­safe REST client for Android built by Square. Using this tool android developer can make all network stuff much more easier. As an example, we are going to download some json and show it in RecyclerView as a list.

1. Creating New Project

android working with retrofit

1. Create a new project in Android Studio from File ⇒ New ⇒ New Project. When it prompts you to select the default activity, select Empty Activity and proceed.

2. Open build.gradle and add RetrofitGson dependencies and compileOptions.

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    // retrofit, gson
    implementation 'com.squareup.retrofit2:retrofit:2.8.1'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
}

3. we are working with network operations we need to add INTERNET permissions in AndroidManifest.xml file.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.codedecode.yashpwr">
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

4. Create four sub packages named activityadapterrest and model in your main package. Move your MainActivity under activity package.

2. Creating Model Class

5. First, we need to know what type of JSON response we will be receiving. Using this route : http://api.codedecode.in/retrofit/movie.json we can get the 20 movies.

6. Create a class named Movie.java under model package.

Movie.java

package com.codedecode.yashpwr.model;

import com.google.gson.annotations.SerializedName;

public class Movie {
    @SerializedName("overview")
    private String overview;
    @SerializedName("release_date")
    private String releaseDate;
    @SerializedName("title")
    private String title;
    @SerializedName("vote_average")
    private Double voteAverage;

    public Movie( String overview, String releaseDate, String title, Double voteAverage) {
        this.overview = overview;
        this.releaseDate = releaseDate;
        this.title = title;
        this.voteAverage = voteAverage;
    }

    public String getOverview() {
        return overview;
    }

    public String getReleaseDate() {
        return releaseDate;
    }

    public String getTitle() {
        return title;
    }

    public Double getVoteAverage() {
        return voteAverage;
    }
}

7. Also we need to create MovieResponse.java class, since we have some extra field like results. This class contains all fetched movies and extra information. Create MovieResponse.java under model package.

MovieResponse.java

package com.codedecode.yashpwr.model;

import com.google.gson.annotations.SerializedName;
import java.util.List;

public class MoviesResponse {
    @SerializedName("results")
    private List<Movie> results;

    public List<Movie> getResults() {
        return results;
    }
}

3. Creating the Retrofit instance

8. To send network requests to an API, we need to use the Retrofit Builder class and specify the base URL for the service. So, create a class named ApiClient.java under rest package.

Here BASE_URL is basic URL of our API. We will use this URL for all requests later.

ApiClient.java

package com.codedecode.yashpwr.rest;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ApiClient {

    public static final String BASE_URL = "http://api.codedecode.in";
    private static Retrofit retrofit = null;


    public static Retrofit getClient() {
        if (retrofit==null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

4. Define the Endpoints

The endpoints are defined inside of an interface using special retrofit annotations to encode details about the parameters and request method. In addition, the return value is always a parameterized Call<T> object such as Call<MovieResponse>. For instance, the interface defines each endpoint in the following way.

9. Create ApiInterface.java under rest package.

ApiInterface.java

package com.codedecode.yashpwr.rest;

import com.codedecode.yashpwr.model.MoviesResponse;
import retrofit2.Call;
import retrofit2.http.GET;

public interface ApiInterface {
    @GET("/retrofit/movie.json")
    Call<MoviesResponse> getTopRatedMovies();
}

So, using this route the retrofit will generate the following URL: http://api.codedecode.in/retrofit/movie.json

Each endpoint specifies an annotation of the HTTP method (GET, POST, etc.) and the parameters of this method can also have special annotations (@Query, @Path, @Body etc.)

Take a look to other annotations:

  • @Path – variable substitution for the API endpoint. For example movie id will be swapped for{id} in the URL endpoint.
  • @Query – specifies the query key name with the value of the annotated parameter.
  • @Body – payload for the POST call
  • @Header – specifies the header with the value of the annotated parameter

5. Making the First Request

10. Let’s make the first request from our MainActivity. If we want to consume the API asynchronously, we call the service as follows. Open the MainActivity.java and do the below changes.

MainActivity.java

package com.codedecode.yashpwr.activity;

import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.codedecode.yashpwr.R;
import com.codedecode.yashpwr.adapter.MoviesAdapter;
import com.codedecode.yashpwr.model.Movie;
import com.codedecode.yashpwr.model.MoviesResponse;
import com.codedecode.yashpwr.rest.ApiClient;
import com.codedecode.yashpwr.rest.ApiInterface;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.movies_recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        ApiInterface apiService =
                ApiClient.getClient().create(ApiInterface.class);

        Call<MoviesResponse> call = apiService.getTopRatedMovies();
        call.enqueue(new Callback<MoviesResponse>() {
            @Override
            public void onResponse(@NonNull Call<MoviesResponse> call, @NonNull Response<MoviesResponse> response) {
                List<Movie> movies = response.body().getResults();
                recyclerView.setAdapter(new MoviesAdapter(movies, R.layout.list_item_movie, getApplicationContext()));
            }

            @Override
            public void onFailure(@NonNull Call<MoviesResponse> call, @NonNull Throwable t) {
                // Log error here since request failed
                Log.e(TAG, t.toString());
            }
        });
    }
}

Retrofit will download and parse the API data on a background thread, and then return the results back to the UI thread via the onResponse or onFailure method.

Congratulations! We have created our first rest client. Let’s create some UI in order to see our results.

6. Displaying the Results in RecyclerView

11. Let’s create ListView for fetched results. We will use RecyclerView for it. First of all, add it to the gradle.gradle.

dependencies {
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
}

In order to show fetched items we need to create layout, which will show all data. We need 4 TextView and 1 ImageView for star image.

12. Open colors.xml and add the below color values.

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="orange">#FF3909</color>
    <color name="colorAccentDark">#00B482</color>
    <color name="colorBlack">#555555</color>
    <color name="colorWhite">#FFFFFF</color>
    <color name="colorGrey">#707070</color>
    <color name="colorGreyLight">#8A8A8A</color>
</resources>

13. Create a layout named star.xml under res/drawable with the below content.

star.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="24"
    android:viewportWidth="24">
    <path
        android:fillColor="#000"
        android:pathData="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z" />
</vector>

14. Create a layout named list_item_movie.java under res layout.

list_item_movie.java

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/movies_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:minHeight="72dp"
    android:orientation="horizontal"
    android:padding="16dp">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingRight="16dp"
            android:textStyle="bold"
            android:textColor="@color/colorBlack"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/subtitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingRight="16dp"
            android:textColor="@color/colorGreyLight" />

        <TextView
            android:id="@+id/description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:maxLines="3"
            android:paddingRight="16dp"
            android:textColor="@color/colorGreyLight" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="35dp"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/rating_image"
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_centerInParent="true"
            android:scaleType="centerCrop"
            android:src="@drawable/star"
            android:tint="@color/colorAccent" />
        <TextView
            android:id="@+id/rating"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:text="5.0" />
    </LinearLayout>

</LinearLayout>

15. Adapter is a common pattern which helps to bind view and data, so let’s implement adapter for this. Create a class named MoviesAdapter.java under adapter package.

MoviesAdapter.java

package com.codedecode.yashpwr.adapter;

import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.codedecode.yashpwr.R;
import com.codedecode.yashpwr.model.Movie;
import java.util.List;

public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MovieViewHolder> {

    private List<Movie> movies;
    private int rowLayout;

    static class MovieViewHolder extends RecyclerView.ViewHolder {
        LinearLayout moviesLayout;
        TextView movieTitle;
        TextView data;
        TextView movieDescription;
        TextView rating;

        MovieViewHolder(View v) {
            super(v);
            moviesLayout = v.findViewById(R.id.movies_layout);
            movieTitle = v.findViewById(R.id.title);
            data = v.findViewById(R.id.subtitle);
            movieDescription = v.findViewById(R.id.description);
            rating = v.findViewById(R.id.rating);
        }
    }

    public MoviesAdapter(List<Movie> movies, int rowLayout, Context context) {
        this.movies = movies;
        this.rowLayout = rowLayout;
    }

    @NonNull
    @Override
    public MovieViewHolder onCreateViewHolder(ViewGroup parent,
                                                            int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
        return new MovieViewHolder(view);
    }

    @Override
    public void onBindViewHolder(MovieViewHolder holder, final int position) {
        holder.movieTitle.setText(movies.get(position).getTitle());
        holder.data.setText(movies.get(position).getReleaseDate());
        holder.movieDescription.setText(movies.get(position).getOverview());
        holder.rating.setText(movies.get(position).getVoteAverage().toString());
    }

    @Override
    public int getItemCount() {
        return movies.size();
    }
}

Finally Run the app you will show output as below.

Working with Retrofit HTTP Libraryy

 

Download Code

Happy Coding 🙂