Use Retrofit 2 in the Android application

Original author: Gurleen Sethi
  • Transfer
  • Tutorial

Используем Retrofit 2 в Android-приложении


Retrofit is a library for networking that is well-known among Android developers, some even consider it to be a standard in some way. There are a lot of reasons for such popularity: the library perfectly supports the REST API, is easily tested and configured, and requests via the network with its help are completely simple. In this article, I will show you how to configure and use Retrofit to implement networking in your application.


Retrofit Setup


Add the following dependency to the file build.gradle:


implementation 'com.squareup.retrofit2:retrofit:2.4.0'

We will use Gson to convert JSON to POJO. Retrofit provides a dependency that automatically converts JSON to POJO. To do this, add another dependency to the file build.gradle:


implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

If your application is not yet allowed to work with the network, be sure to add the appropriate line to the file AndroidManifest:


<uses-permissionandroid:name="android.permission.INTERNET"/>

After the dependencies are added, we need to write code to customize the Retrofit library.


Create a class named NetworkService:


publicclassNetworkService{
}

This class must be a singleton object, so declare a static variable and a function that creates and returns a variable of the same type as the class. If you do not know how this pattern works, then read this article , which has examples of implementation in the Java language.


publicclassNetworkService{
    privatestatic NetworkService mInstance;
    publicstatic NetworkService getInstance(){
        if (mInstance == null) {
            mInstance = new NetworkService();
        }
        return mInstance;
    }
}

For testing, we use JSONPlaceholder , which provides a fake online REST API for developers:


https://jsonplaceholder.typicode.com

Now we will declare and initialize the Retrofit in the constructor NetworkService:


publicclassNetworkService{
    privatestatic NetworkService mInstance;
    privatestaticfinal String BASE_URL = "https://jsonplaceholder.typicode.com";
    private Retrofit mRetrofit;
    privateNetworkService(){
        mRetrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }
    publicstatic NetworkService getInstance(){
        if (mInstance == null) {
            mInstance = new NetworkService();
        }
        return mInstance;
    }
}

Setup is complete, now we need to define the endpoints that will return data.


Add endpoints


Create an interface named JSONPlaceHolderApi:


publicinterfaceJSONPlaceHolderApi{
}

On the JSONPlaceHolder website , the URL /posts/idis the endpoint that returns a message with the appropriate id. This endpoint accepts a GET request and returns the data in JSON format as follows:


{
  "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 create the corresponding POJO for the JSON response:


publicclassPost{
    @SerializedName("userId")
    @Exposeprivateint userId;
    @SerializedName("id")
    @Exposeprivateint id;
    @SerializedName("title")
    @Exposeprivate String title;
    @SerializedName("body")
    @Exposeprivate String body;
    publicintgetUserId(){
        return userId;
    }
    publicvoidsetUserId(int userId){
        this.userId = userId;
    }
    publicintgetId(){
        return id;
    }
    publicvoidsetId(int id){
        this.id = id;
    }
    public String getTitle(){
        return title;
    }
    publicvoidsetTitle(String title){
        this.title = title;
    }
    public String getBody(){
        return body;
    }
    publicvoidsetBody(String body){
        this.body = body;
    }
}

As you can see, this is a simple POJO class. Variables we annotated with @SerializedName(), passing the name there. These names are actually keys in the JSON data returned from the API, so you can change the name of the variable as you like, but make sure that the name passed to the annotation @SerializedName()is exactly present in JSON.


In the interface created above, define the end points with the required parameters:


publicinterfaceJSONPlaceHolderApi{
    @GET("/posts/{id}")
    public Call<Post> getPostWithID(@Path("id")int id);
}

Since we are sending a GET request, we need to apply an annotation to the method @GET, inside which there is an endpoint to which we want to send a request. As you can see, we are not adding the full URL, because Retrofit will automatically take the BASE_URLpassed in class NetworkServiceand add it to the rest of the URL.


The return type of the method is called Call<Post>. CallIs a class provided directly by the library itself. And all methods in the interface should return values ​​of this type. This is a generic class that accepts the type of object that we want to convert to JSON. We passed Post, because This is exactly the object that we want to convert the JSON response to. We passed an integer to the parameters and annotated it with the help @Pathinside which we wrote it id. Retrofit will take this value and replace it at the end point {id}. Thus, if we pass the value 1 as a parameter, then the end point will look like this - /posts/1if we pass the value 10, then the end point will turn out to be - /posts/10.


Now we need to Retrofit to provide an interface implementation JSONPlaceHolderApi. For this we use the method create():


publicclassNetworkService{
    privatestatic NetworkService mInstance;
    privatestaticfinal String BASE_URL = "https://jsonplaceholder.typicode.com";
    private Retrofit mRetrofit;
    privateNetworkService(){
        mRetrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }
    publicstatic NetworkService getInstance(){
        if (mInstance == null) {
            mInstance = new NetworkService();
        }
        return mInstance;
    }
    public JSONPlaceHolderApi getJSONApi(){
        return mRetrofit.create(JSONPlaceHolderApi.class);
    }
}

Next you need to get JSONPlaceHolderApiout NetworkServiceand send a request:


NetworkService.getInstance()
                .getJSONApi()
                .getPostWithID(1)
                .enqueue(new Callback<Post>() {
                    @OverridepublicvoidonResponse(@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");
                    }
                    @OverridepublicvoidonFailure(@NonNull Call<Post> call, @NonNull Throwable t){
                        textView.append("Error occurred while getting request!");
                        t.printStackTrace();
                    }
                });

The returned object Callcontains a method with a name enqueuethat takes as a parameter Callback<T>. As onResponsewe get a result Response<Post>that contains an object returned from the server Post. To get the object itself Post, use the method response.body(). The rest of the code is understandable without further explanation.


Sending various types of requests


The API JSONPlaceHolderhas many different endpoints that you can use.


Getting a list of messages


@GET("/posts")
public Call<List<Post>> getAllPosts();

To get a list of all messages, we changed the end point and the return type of the function.


Sending request with parameter


If you want to send a request with a parameter, then you only need to use the annotation @Query()for the corresponding parameter in the method:


@GET("/posts")
public Call<List<Post>> getPostOfUser(@Query("userId") int id);

Therefore, if we pass the value 6 in the method parameter, then the end point will be next - /posts?userId=6.


Sending a POST request


To send a POST request, you just need to change the method annotation.


@POST("/posts")
public Call<Post> postData(@Body Post data);

To form the request body for this method, we use the annotation @Bodyfor the passed parameter. Retrofit will use Gson to convert @Bodyto JSON.


There are several other types of queries that you can use, but this is a topic for a separate article.


Intercept requests


Retrofit provides a way to capture requests and log them to Logcat. Let's set up an interceptor and look at this magic. Add the following dependency to the file build.gradle:


implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'

Update the class NetworkServicethis way:


publicclassNetworkService{
    privatestatic NetworkService mInstance;
    privatestaticfinal String BASE_URL = "https://jsonplaceholder.typicode.com";
    private Retrofit mRetrofit;
    privateNetworkService(){
        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();
    }
    publicstatic NetworkService getInstance(){
        if (mInstance == null) {
            mInstance = new NetworkService();
        }
        return mInstance;
    }
    public JSONPlaceHolderApi getJSONApi(){
        return mRetrofit.create(JSONPlaceHolderApi.class);
    }
}

Now, when you send or receive a request, all its data, including URLs, headers, body, will be displayed in the log:


D/OkHttp: <--200https://jsonplaceholder.typicode.com/posts/1 (3030ms)
    date:Tue, 24Apr201815:25:19GMTcontent-type:application/json; charset=utf-8set-cookie:__cfduid=d16d4221ddfba20b5464e6829eed4e3d11524583519;expires=Wed,24-Apr-1915:25:19GMT; path=/;domain=.typicode.com;HttpOnlyx-powered-by:Expressvary:Origin, Accept-Encodingaccess-control-allow-credentials:truecache-control:public, max-age=14400pragma:no-cacheexpires:Tue, 24Apr201819:25:19GMT04-2415:25:16.2047023-7056/com.thetehnocafe.gurleensethi.retrofitexampleD/OkHttp:x-content-type-options:nosniffetag:W/"124-yiKdLzqO5gfBrJFrcdJ8Yq0LGnU"
    via:1.1vegurcf-cache-status:HITexpect-ct:max-age=604800,report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"server:cloudflarecf-ray:410994f328963066-SIN04-2415:25:16.2467023-7056/com.thetehnocafe.gurleensethi.retrofitexampleD/OkHttp: {
04-2415:25:16.2477023-7056/com.thetehnocafe.gurleensethi.retrofitexampleD/OkHttp:   "userId":1,
      "id":1,
      "title": "suntautfacererepellatprovidentoccaecatiexcepturioptioreprehenderit",
      "body": "quiaetsuscipit\nsuscipitrecusandaeconsequunturexpeditaetcum\nreprehenderitmolestiaeututquastotam\nnostrumrerumestautemsuntremevenietarchitecto"
    }
    <--ENDHTTP (292-bytebody)

This is where our article ends. You can find the code for this project on GitHub .


Also popular now: