Retrofit is a well known networking library among Android Developers, some even consider it as the industry standard. There are many reasons why it is so popular, great support for REST API’s, easily testable, easy to set up and make network calls. In this tutorial I will show you how to set up and use Retrofit to meet your app’s networking needs.
Setting up retrofit
Add the following dependency in your build.gradle file.
1 |
compile 'com.squareup.retrofit2:retrofit:2.4.0' |
We will using Gson to convert JSON into our POJO’s. Retrofit provides a dependency that will automatically convert JSON into POJO for us. Add the following dependency in your build.gradle file.
1 |
compile 'com.squareup.retrofit2:converter-gson:2.3.0' |
If your project doesn’t declare the Internet permission, then please do so immediately in your Manifest.
1 |
<uses-permission android:name="android.permission.INTERNET"/> |
Now that we are done adding dependencies, lets write some code which is required to set up Retrofit.
Create a class named NetworkService .
1 2 3 |
public class NetworkService { } |
This class will be a singleton, so declare a static variable and a function that assigns and returns the value of the variable of the same type. Please read about Singleton in Java if you don’t know about this pattern.
1 2 3 4 5 6 7 8 9 10 |
public class NetworkService { private static NetworkService mInstance; public static NetworkService getInstance() { if (mInstance == null) { mInstance = new NetworkService(); } return mInstance; } } |
For testing purposes, we are using JSONPlaceholder which provides fake online REST API for developers.
1 |
https://jsonplaceholder.typicode.com |
Now we will declare and initialise Retrofit in the constructor of NetworkService.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class NetworkService { private static NetworkService mInstance; private static final String BASE_URL = "https://jsonplaceholder.typicode.com"; private Retrofit mRetrofit; private NetworkService() { mRetrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); } public static NetworkService getInstance() { if (mInstance == null) { mInstance = new NetworkService(); } return mInstance; } } |
The set up is complete, now we need to define the end points that will return some kind of data.
Adding end points
Create an interface named JSONPlaceHolderApi .
1 2 3 |
public interface JSONPlaceHolderApi { } |
In the JSONPlaceHolder website /posts/id is the end point that returns the post with the corresponding ID. This end point takes a GET request and returns the JSON data in the following format:
1 2 3 4 5 6 |
{ "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" } |
First we will make a corresponding POJO for the JSON response.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
public class Post { @SerializedName("userId") @Expose private int userId; @SerializedName("id") @Expose private int id; @SerializedName("title") @Expose private String title; @SerializedName("body") @Expose private String body; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } } |
As you can see this is a simple POJO class. We have annotated the variables with @SerializedName() and passed in a name, these passed names are the actual keys in the returned JSON data from api, so you are free to change the variable name to whatever you like but make sure the that name passed in SerializedName annotation is exactly what is present in JSON.
In the interface created above, define the end point with required parameters.
1 2 3 4 |
public interface JSONPlaceHolderApi { @GET("/posts/{id}") public Call<Post> getPostWithID(@Path("id") int id); } |
Since we are sending a GET request, we have annotate the method with a @GET annotation, inside it we have passed the end point that we want to send the request to. You can see we haven’t added the complete URL, Retrofit will automatically take the BASE_URL that you passed in NetworkService class and append it with the remaining url.
The return type of method is Call<Post> . Call is a class provided by Retrofit itself which should be the return type of all the methods in the interface, Call is a generic class and takes the type of object we want the JSON to be converted to, we have passed Post since that is what we want the JSON response to be converted to. In the parameters we have passed in an integer and annotated it with @Path in the path we have written id, what Retrofit will do is that the value passed as the parameter and replace it instead of the {id} in the end point, so if we pass 1 as the parameter value, the end point generated will be /posts/1 , if we pass 10 it will become /posts/10 .
Now we want Retrofit to provide us with the implementation of our JSONPlaceHolderApi interface. We do this by using the create() method on Retrofit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class NetworkService { private static NetworkService mInstance; private static final String BASE_URL = "https://jsonplaceholder.typicode.com"; private Retrofit mRetrofit; private NetworkService() { mRetrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); } public static NetworkService getInstance() { if (mInstance == null) { mInstance = new NetworkService(); } return mInstance; } public JSONPlaceHolderApi getJSONApi() { return mRetrofit.create(JSONPlaceHolderApi.class); } } |
Now we need to get the JSONPlaceHolderApi from NetworkService and send the request.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
NetworkService.getInstance() .getJSONApi() .getPostWithID(1) .enqueue(new Callback<Post>() { @Override public void onResponse(@NonNull Call<Post> call, @NonNull Response<Post> response) { Post post = response.body(); textView.append(post.getId() + "\n"); textView.append(post.getUserId() + "\n"); textView.append(post.getTitle() + "\n"); textView.append(post.getBody() + "\n"); } @Override public void onFailure(@NonNull Call<Post> call, @NonNull Throwable t) { textView.append("Error occurred while getting request!"); t.printStackTrace(); } }); |
The returned
Call object has a method named
enqueue that takes in a
Callback<T> . In
onResponse we get the result
Response<Post> that contains our retuned Post object from server. We get the Post object by calling
response.body() . Rest of the code is pretty self explanatory.
Sending different types of request
JSONPlaceHolder Api has various end points that we can call.
Fetching list of Posts (GET)
1 2 |
@GET("/posts") public Call<List<Post>> getAllPosts(); |
When getting list of all posts, we changed the end point and also the return type of function.
Sending a query parameter
When you need to send a query parameter, all you need to do is annotate the promoter of function with @Query() .
1 2 |
@GET("/posts") public Call<List<Post>> getPostOfUser(@Query("userId") int id); |
So if we pass 6 as the value in method parameter, the end point generated will be /posts?userId=6
Sending a POST request
To send a POST POST request all you need to change is the method annotation.
1 2 |
@POST("/posts") public Call<Post> postData(@Body Post data); |
In POST requests many times we need to send a body, we do that by just adding a method parameter and annotating it with @Body .Retrofit will use GSON to convert this object to JSON.
There are various types of Requests that you can send, convening all of them is out of scope of this article.
Intercepting Requests
Retrofit provides a way to intercept Requests and log them in Logcat. Lets set up the Interceptor and see its magic. Add the following dependency in the build.gradle file.
1 |
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0' |
Update the NetworkService class and add the highlighted code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class NetworkService { private static NetworkService mInstance; private static final String BASE_URL = "https://jsonplaceholder.typicode.com"; private Retrofit mRetrofit; private NetworkService() { HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient.Builder client = new OkHttpClient.Builder() .addInterceptor(interceptor); mRetrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .client(client.build()) .build(); } public static NetworkService getInstance() { if (mInstance == null) { mInstance = new NetworkService(); } return mInstance; } public JSONPlaceHolderApi getJSONApi() { return mRetrofit.create(JSONPlaceHolderApi.class); } } |
Now whenever you send/receive a request, all of its details such as URL, Headers, Body will be logged.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
D/OkHttp: <-- 200 https://jsonplaceholder.typicode.com/posts/1 (3030ms) date: Tue, 24 Apr 2018 15:25:19 GMT content-type: application/json; charset=utf-8 set-cookie: __cfduid=d16d4221ddfba20b5464e6829eed4e3d11524583519; expires=Wed, 24-Apr-19 15:25:19 GMT; path=/; domain=.typicode.com; HttpOnly x-powered-by: Express vary: Origin, Accept-Encoding access-control-allow-credentials: true cache-control: public, max-age=14400 pragma: no-cache expires: Tue, 24 Apr 2018 19:25:19 GMT 04-24 15:25:16.204 7023-7056/com.thetehnocafe.gurleensethi.retrofitexample D/OkHttp: x-content-type-options: nosniff etag: W/"124-yiKdLzqO5gfBrJFrcdJ8Yq0LGnU" via: 1.1 vegur cf-cache-status: HIT expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" server: cloudflare cf-ray: 410994f328963066-SIN 04-24 15:25:16.246 7023-7056/com.thetehnocafe.gurleensethi.retrofitexample D/OkHttp: { 04-24 15:25:16.247 7023-7056/com.thetehnocafe.gurleensethi.retrofitexample D/OkHttp: "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" } <-- END HTTP (292-byte body) |
That is it for this tutorial. You can find the code for this project on GitHub here.
A complete guide to integrating AdMob in your Android App.
Understanding LiveData in Android Architecture Components.