Sending Data With Retrofit 2 HTTP Client for Android

Final product image
What You'll Be Creating

What Is Retrofit?

Retrofit is a type-safe HTTP client for Android and Java. Retrofit makes it easy to connect to a REST web service by translating the API into Java interfaces. In this tutorial, I'll show you how to use one of the most popular and often recommended HTTP libraries available for Android.

This powerful library makes it easy to consume JSON or XML data, which is then parsed into Plain Old Java Objects (POJOs). GETPOSTPUTPATCH, and DELETE requests can all be executed. 

Like most open-source software, Retrofit was built on top of some other powerful libraries and tools. Behind the scenes, Retrofit makes use of OkHttp (from the same developer) to handle network requests. Also, Retrofit does not have a built-in JSON converter to parse from JSON to Java objects. Instead, it ships support for the following JSON converter libraries to handle that:

  • Gson: com.squareup.retrofit:converter-gson
  • Jackson: com.squareup.retrofit:converter-jackson
  • Moshi: com.squareup.retrofit:converter-moshi

For Protocol buffers, Retrofit supports:

  • Protobuf: com.squareup.retrofit2:converter-protobuf
  • Wire: com.squareup.retrofit2:converter-wire

And for XML Retrofit, supports:

  • Simple Framework: com.squareup.retrofit2:converter-simpleframework

So Why Use Retrofit?

Developing your own type-safe HTTP library to interface with a REST API can be a real pain: you have to handle many aspects, such as making connections, caching, retrying failed requests, threading, response parsing, error handling, and more. Retrofit, on the other hand, is a well-planned, documented and tested library that will save you a lot of precious time and headaches.

In this tutorial, I will explain how to use Retrofit 2 to handle network requests by building a simple app that will perform POST requests, PUT requests (to update entities), and DELETE requests. I'll also show you how to integrate with RxJava and how to cancel requests. We'll be using the API provided by JSONPlaceholder—this is a fake online REST API for testing and prototyping.

Check out my previous post, Get Started With Retrofit 2 HTTP Client, to learn how to execute GET requests and how to integrate Retrofit with RxJava. 

1. Create an Android Studio Project

Fire up Android Studio and create a new project with an empty activity called MainActivity.

create a new empty activity

2. Declaring Dependencies

After creating a new project, declare the following dependencies in your build.gradle. The dependencies include the Retrofit library and also Google's Gson library to convert JSON to POJO (Plain Old Java Objects) as well as Retrofit's Gson integration. 

Make sure you sync your project after adding the dependencies. 

3. Adding Internet Permission

To perform network operations, we need to include the INTERNET permission in the application manifest: AndroidManifest.xml.

4. Generating Models Automatically

We are going to create models automatically from the JSON response data by leveraging a very useful tool: jsonschema2pojo. We would like to make a POST request (create a new resource) on the API. But before we execute this request, we need to know the JSON response we should expect when it is executed successfully so that Retrofit can parse the JSON response and deserialize it to Java objects. According to the API, if we send the following data in a POST request:

We should get the following response:

Map the JSON Data to Java 

Copy the sample response data from the previous section. Now visit  jsonschema2pojo and paste the JSON response into the input box. Select source type of JSON, annotation style of Gson, uncheck Allow additional properties, and change the class name from Example to Post

jsonschema2pojo input

Then click the Preview button to generate the Java objects. 

jsonschema2pojo output

You might be wondering what the @SerializedName and @Expose annotations do in this generated code! Don't worry, I'll explain it all!

The @SerializedName annotation is needed for Gson to map the JSON keys to Java object fields.

In this case, the JSON key userId is mapped to the class field userId. But note that since they are the same, there is no need to include the @SerializedName annotation on the field because Gson will map it automatically for us.

The @Expose annotation indicates that the class member should be exposed for JSON serialization or deserialization. 

Import Data Models to Android Studio

Now let's go back to Android Studio. Create a new sub-package inside the main package and name it data. Inside the newly created package, create another package and name it model. Inside this package, create a new Java class and name it Post. Now copy the Post class that was generated by jsonschema2pojo and paste it inside the Post class you created. 

Apart from the getters and setters, I also included the toString() method. (In Intellij, you can use the Generate command to make this easy: Alt-Insert on Windows, or Command-N on macOS.)

5. Creating the Retrofit Instance

To issue network requests to a RESTful API with Retrofit, we need to create an instance using the Retrofit Builder class and configure it with a base URL. 

Create a new sub-package inside the data package and name it remote. Now, inside this package, create a Java class and name it RetrofitClient. This class will create a singleton of Retrofit in the method getClient(String baseUrl) and return it to the caller. 

As I mentioned earlier, Retrofit needs a base URL to build its instance, so we will pass it a URL when calling RetrofitClient.getClient(String baseUrl). This URL will then be used to build the instance in line 12. We are also specifying the JSON converter we need (Gson) in line 13. 

6. Creating the API Interface

Inside the remote package, create an interface and call it APIService. This interface contains methods we are going to use to execute HTTP requests such as POSTPUT, and DELETE. Let's start with the POST request.  

Looking at the APIService class, we have a method called savePost(). On top of the method is the @POST annotation, which indicates that we want to execute a POST request when this method is called. The argument value for the @POST annotation is the endpoint—which is /posts. So the full URL will be http://jsonplaceholder.typicode.com/posts

Okay, so what about the @FormUrlEncoded? This will indicate that the request will have its MIME type (a header field that identifies the format of the body of an HTTP request or response) set to application/x-www-form-urlencoded and also that its field names and values will be UTF-8 encoded before being URI-encoded. The @Field("key") annotation with parameter name should match the name that the API expects. Retrofit implicitly converts the values to strings using String.valueOf(Object), and the strings are then form URL encoded. null values are ignored. 

For example, calling APIService.savePost("My Visit To Lagos", "I visited...", 2) yields a request body of title=My+Visit+To+Lagos&body=I+visited...&userId=2.

Using the @Body Annotation

We can also use the @Body annotation on a service method parameter instead of specifying a form-style request body with a number of individual fields. The object will be serialized using the Retrofit instance Converter specified during creation. This is only used when performing either a POST or PUT operation. 

7. Creating the API Utilities

We are going to create a utility class. So create a class in data.remote and name it ApiUtils. This class will have the base URL as a static variable and will also provide the APIService interface by with a getAPIService() static method to the rest of our application.

Make sure you end the base URL with a /

8. Creating the Layout

The file activity_main.xml is the layout for our MainActivity. This layout will have one text edit field for the title of the post and another for the body of the post. It also includes a button to submit the post to the API. 

9. Executing the POST request

In the onCreate() method in MainActivity, we initialize an instance of the APIService interface (line 14). We also initialize the EditText fields and a submit button that will call the sendPost() method when clicked (line 22).

In the sendPost(String, String) method in the MainActivity class, we passed in the title and body of the post to this method. What this method will do is call our API service interface method savePost(String, String) whose job is to execute a POST request sending the title and body to the API. The showResponse(String response) method will display the response on the screen.

Our APIService instance mAPIService method savePost(String, String) will return a Call instance which has a method called enqueue(Callback<T> callback).

Understanding enqueue()

enqueue() asynchronously sends the request and notifies your app with a callback when a response comes back. Since this request is asynchronous, Retrofit handles the execution on a background thread so that the main UI thread isn't blocked or interfered with. 

To use the enqueue() method, you have to implement two callback methods: onResponse() and onFailure(). Only one of these methods will be called in response to a given request. 

  • onResponse(): invoked for a received HTTP response. This method is called for a response that can be correctly handled even if the server returns an error message. So if you get a status code of 404 or 500, this method will still be called. To get the status code in order for you to handle situations based on them, you can use the method response.code(). You can also use the isSuccessful() method to find out if the status code is in the range 200-300, indicating success.
  • onFailure(): invoked when a network exception occurred communicating to the server or when an unexpected exception occurred handling the request or processing the response.

Synchronous Requests

To perform a synchronous request, you can use the execute() method in a Call instance. But be aware that synchronous methods on the main/UI thread will block any user action. So don't execute synchronous methods on Android's main/UI thread! Instead run them on a background thread.

Using RxJava 

RxJava was integrated into Retrofit 1 by default, but in Retrofit 2 you need to include some extra dependencies. Retrofit ships with a default adapter for executing Call instances. So you can change Retrofit's execution mechanism to include RxJava by including the RxJava CallAdapter. These are the steps:

Step 1

Add the dependencies.

Step 2

Add the new CallAdapter RxJavaCallAdapterFactory.create() when building a Retrofit instance (line 5).  

Step 3

Update the APIService savePost(String title, String body, String userId) method to become an Observable. 

Step 4

When making the requests, our anonymous subscriber responds to the observable's stream which emits events, in our case Post. The onNext method is then called when our subscriber receives any event, which is then passed to our showResponse(String response) method. 

Check out Getting Started With ReactiveX on Android by Ashraff Hathibelagal to learn more about RxJava and RxAndroid. 

10. Testing the App

At this point, you can run the app and click the submit button when you have entered a title and body. The response from the API will show below the submit button. 

final app screenshot

11. Executing a PUT request

Now that we know how to execute a POST request, let's see how we can execute a PUT request which updates entities.  Add the following new method to the APIService class. 

To update a post from the API, we have the endpoint /posts/{id} with {id} being a placeholder for the id of the post we want to update. The @Path annotation is the named replacement in a URL path segment {id}. Be aware that values are converted to string using String.valueOf(Object) and URL encoded. If the value is already encoded, you can disable URL encoding like this: @Path(value="name", encoded=true)

12. Executing a DELETE request

Let's also see how to execute a DELETE request. Using the JSONPlaceholder  API, to delete a post resource, the required endpoint is /posts/{id} with the HTTP method DELETE. Back to our APIService interface, we just need to include the method deletePost() that will execute it.  We pass in the id of the post to the method, and it is replaced in the URL path segment {id}.

13. Canceling a Request

Let's say you want to give your users the ability to cancel or abort a request. This is very easy to do in Retrofit. The Retrofit Call class has a method called cancel() that will do just that (line 32 below). This method will trigger the onFailure() method in the callback. 

This method can be called, for example, if there is no internet connection or when an unexpected exception occurred creating the request or handling the response. So to know if the request was canceled, use the method isCanceled() in the Call class (line 20). 

Conclusion

In this tutorial, you learned about Retrofit: why you should use it and how to integrate it in your project to perform POSTPUTDELETE and cancel requests. You also learned how to integrate RxJava with it. In my next post in using Retrofit, I'll show you how to upload files. 

To learn more about Retrofit, do refer to the official documentation. And check out some of our other tutorials and courses about Android development here at Envato Tuts+!

Tags:

Comments

Related Articles