Preamble: You either strike out or you’re out. Fortune favors the one who tries his best.

An overview,

1. What is Retrofit

Retrofit is a popular web request framework that can be understood as an enhanced version of OKHTTP that encapsulates okHTTP underneath. To be precise, Retrofit is an encapsulation of a RESTful HTTP Web request framework. Because the web request work is essentially done by OKHTTP, Retrofit is responsible for encapsulating the web request interface.

Essential process: App applications make requests through the Retrofit network, essentially encapsulating the request parameters, headers, urls, etc., using the Retrofit interface layer, and then okHTTP completes subsequent requests. After the server returns the data, OkHTTP hands the raw data to Retrofit, which parses it based on user requirements.

2. Benefits of Retrofit

  • Super decoupling: interface definitions, interface parameters, and interface callbacks are no longer coupled together
  • Different HttpClients can be configured to implement network requests, such as okHTTP and httpClient
  • Supports synchronous, asynchronous, and Rxjava
  • You can configure different deserialization utility classes to parse different data, such as JSON and XML
  • Request fast, easy to use flexible and simple

Second, the annotation

Retrofit uses extensive annotations to simplify requests. Retrofit abstracts OKHTTP requests into Java interfaces, using annotations to configure and describe network request parameters. Probably can be divided into the following categories, we first look at the meaning of each annotation, and then to practice interpretation.

1. Request method annotations

Request method annotations instructions
@GET A get request
@POST A post request
@PUT Put request
@DELETE The delete request
@PATCH Patch request, which is a complement to the PUT request and is used to update local resources
@HEAD A head request
@OPTIONS The options request
@HTTP All of the above annotations can be replaced by annotations, which have three attributes: Method, Path, and hasBody

2. Request header annotations

Request header annotation instructions
@Headers For adding fixed headers, you can add more than one at a time. Headers passing this annotation do not overwrite each other, but coexist
@Header Passed as a parameter to the method, used to add a non-fixed header that updates the existing request header

3. Request parameter annotations

Request parameter annotations instructions
@Body It is mostly used to send non-expressive data in Post requests. The instance object is converted into the corresponding string to pass parameters according to the conversion method, such as sending Json data using Post, and adding GsonConverterFactory converts the body into a Json string to pass
@Filed It is usually used to transfer parameters in Post mode, which needs to be combined with @fromurlencoded, that is, parameters are transmitted in form
@FiledMap It is used for form fields in Post requests and should be used in conjunction with @fromurlencoded
@Part For form fields, parts and PartMap are used in conjunction with @multiPart annotations, suitable for file upload situations
@PartMap For form fields, the default acceptance type is Map<String,RequestBody>, which can be used to implement multiple file uploads
@Path Used as a placeholder in a Url
@Query Parameters used in Get requests
@QueryMap Similar to Query, used to determine form parameters
@Url Specify the request path

4. Request and response format (markup) annotations

Tag class annotation instructions
@FromUrlCoded Field represents the request to send encoded form data. Each key value pair needs to use the @filed annotation
@Multipart Request to send form_encoded data (used in file upload scenarios), each key-value pair needs to annotate the key name with @part, and subsequent objects need to provide a value
@Streaming The response is returned as a byte stream, which by default loads all the data into memory without annotations, especially useful when downloading large files

Use of Retrofit

Let’s start by explaining the use of annotations and the issues to be aware of (detailed instructions will be given later). As mentioned above, annotations are used to configure and describe network request parameters. Let’s go through them one by one.

  • Retrofit abstracts okHTTP requests into Java interfaces, describes and configures network request parameters with annotations, “translates” the interface’s annotations into an Http request using a dynamic proxy, and finally executes the Http request.
  • Note: The parameters of each method in the interface must be annotated, otherwise an error will be reported.

1. Detailed explanation of notes

1) The use of @get, @query and @queryMap

public interface Api {
    / / get request
    @GET("user")
    Call<ResponseBody> getData(a);
}
Copy the code
  • @get request method annotation, GET request, and in parentheses is the request address, part of the Url
  • Call<*> return type, * represents the class to receive data, generally custom
  • GetData () interface method name, with arguments in parentheses

The network interface above is the simplest form, so let’s start with the simplest and work our way through it. This is a get request with no network parameters. The @get annotation in the method header indicates that the get method is used to access the network request, and the address (part of the Url) in parentheses is the request address. The return type is Call<*>, and the * indicates the class that received the data. Call

; Call

; Call

;


Specifically describing the composition of urls (as explained below), Retrofit sets up the Url for web requests in two parts: The first part is set through.baseurl () when creating a Retrofit instance, and the second part is set in network interface annotations, such as “/user” for the interface above, the full address of the network request Url = Retrofit instence.baseurl ()+ Network request interface annotations ().

Let’s look at the get request method with parameters:

 @GET("user")
 Call<ResponseBody> getData2(@Query("id") long idLon, @Query("name") String nameStr);
Copy the code
  • @query Request parameter annotation, used for parameters in Get requests
  • The “ID “/”name” parameter field must be the same as the field provided in the background
  • Long /String Specifies the declared parameter type
  • IdLon /nameStr Specifies the actual parameter

Add the parameter @query to the method parentheses, followed by the parameter type and the parameter field, indicating that the value of idLon is the value of “ID” and the value of nameStr is the value of “name”, which is essentially a key-value pair. Retrofit concatenates the two fields into the interface and appends them to “/user”. For example: baseUrl is api.github.com/, then the address in the annotation of network interface will be changed to api.github.com/user, we need to pass in id=10006, name=” Liu Yifei “, then the complete request address after the concatenation parameter is: https://api.github.com/user?id=10006&name= l.

 @GET("user")
 Call<ResponseBody> getData3(@QueryMap Map<String, Object> map);
Copy the code
  • @QueryMap Request parameter annotations, similar to @Query, are used to determine form parameters
  • Map

    Map Uncertain parameters are passed in through a Map, which is equivalent to multiple Query parameters
    ,>

We can use the @queryMap annotation to add parameters to the form if there are uncertain parameters, store the uncertain parameters in the Map, and then pass them to the network interface in the body of the method.

  Map<String, Object> map = new HashMap<>();
  map.put("id".10006);
  map.put("name"."Liu Yifei");

  Call<ResponseBody> call = retrofit.create(Api.class).getData3(map);
Copy the code

2) the use of @post, @formurlencoded, @file, @filemap, @body

Let’s look at the request for the POST method with no arguments:

@POST("user/emails")
Call<ResponseBody> getPostData(a);
Copy the code
  • @POST request method annotation, indicating that the POST method is used to access network requests, followed by partial URL addresses in parentheses

@POST = post; @post = post; @post = post;

@FormUrlEncoded
@POST("user/emails")
Call<ResponseBody> getPostData2(@Field("name") String nameStr, @Field("sex") String sexStr);
Copy the code
  • @formurlencoded request format annotations, the request entity is a From form, and the @field annotation is required for each key-value pair
  • @field request parameter annotations, form fields for submitting requests, must be added and used with @Formurlencoded
  • The “name”/”sex” parameter field must be the same as the field given in the background
  • String Specifies the declared parameter type
  • NameStr /sexStr Actual parameter, indicating that the value of nameStr is the value of “name” and the value of sexStr is the value of “sex”

If a Post request has parameters, @Formurlencoded annotations are added to the header, indicating that the request entity is a From form, each key-value pair needs to use @field annotation, and @field is used to add parameters, which is required for submitting the form Field when sending the Post request. And it needs to work with @Formurlencoded.

 @FormUrlEncoded
 @POST("user/emails")
 Call<ResponseBody> getPsotData3(@FieldMap Map<String, Object> map);
Copy the code
 Map<String, Object> fieldMap = new HashMap<>();
 map.put("name"."Liu Yifei");
 map.put("sex"."Female");

 Call<ResponseBody> psotData3 = retrofit.create(Api.class).getPostData3(map);
Copy the code
  • @fieldMap request parameter annotation, used in the same way as @field, for indeterminating form parameters
  • Map

    Map Uncertain parameters are passed in through a Map, which is equivalent to multiple Field parameters
    ,>

When there are multiple uncertain parameters, we can use the @fieldMap annotation. @fieldMap has the same function as @field and can be used to add multiple uncertain parameters, similar to @QueryMap, where the Map’s key is the key of the form and the Map’s value is the value of the form.

@body can be used to pass custom types of data to the server for Post requests, such as passing Json data. It can be used to annotate many things, such as hashMaps, entity classes, etc. Let’s see how it is used:

@POST("user/emails")
Call<ResponseBody> getPsotDataBody(@Body RequestBody body);
Copy the code
  • @Body uploads JSON data, passes it directly to the entity and it automatically converts to JSON, as defined by GsonConverterFactory

Note that the @body annotation cannot be used to encode forms or forms that support file uploads, i.e. it cannot be used in conjunction with @formurlencoded and @multipart annotations, otherwise an error will be reported.

We find the @body source code and find that if isFormEncoded is true or isMultipart is true, either of the two conditions will throw the exception. We can see from the variable name that the @Formurlencoded or @Multipart tags are used.

 if (annotation instanceof Body) {
    if (isFormEncoded || isMultipart) {
       throw parameterError(method, p,
          "@Body parameters cannot be used with form or multi-part encoding."); }}Copy the code

3) @ HTTP

The @HTTP annotation replaces @get, @post, @PUT, @delete, @head, and more

@HTTP(method = "GET", path = "user/keys", hasBody = false)
Call<ResponseBody> getHttpData(a);
Copy the code
  • Method means the method of the request, case sensitive, so retrofit doesn’t do anything with this value, it has to be correct
  • Path Network request address path
  • HasBody has a request body, Boolean type

The @http annotation allows you to set the specific request method through the method field, while setting the network request address through path is rarely used. @http replaces @post, @put, @delete, @head, and so on in a similar way, which I won’t explain here.

4) @ Path

 @GET("orgs/{id}")
 Call<ResponseBody> getPathData(@Query("name") String nameStr, @Path("id") long idLon);
Copy the code
  • The @query get annotation of the request method parameter, as explained above, will not be repeated here
  • @path request parameter annotation, used for placeholder {} in Url, all parameters in Url

The @path annotation is used for placeholders {} in urls. All parameters in urls, such as the id of @get (“orgs/{id}”) above, are marked with the id of the {} placeholder. The @path annotation is used to pass in the value of idLon. The key value pairs that follow are actually shared by @query and @path. When the request is initiated, {id} is replaced with the value idLon, the second parameter in the method.

5) @ Url

If you need to re-address the interface address, you can use @URL and pass in the address as a parameter. If there is an @Url annotation, the Url passed by GET can be omitted.

@GET
Call<ResponseBody> getUrlData(@Url String nameStr, @Query("id") long idLon);
Copy the code
  • @Url specifies the request path and can be passed in as a parameter

6) @Headers, @Headers

We can add a request Header to a method parameter. @header is used to add a non-fixed request Header, which is passed in as a method parameter. This annotation updates the existing request Header.

 @GET("user/emails")
 Call<ResponseBody> getHeaderData(@Header("token") String token);
Copy the code
  • @header Request header annotation, used to add a non-fixed request header

If you want to add a fixed headers to a method, you can use @headers to add a fixed headers to a method. You can add more than one headers to a method at the same time. Headers added through this annotation do not overwrite each other.

 @ Headers ({phone - type: "android", "version: 1.1.1"})
 @GET("user/emails")
 Call<ResponseBody> getHeadersData(a);
Copy the code
  • The @headers request header annotation is used to add a fixed request header. You can add more headers

7) @ Streaming

 @Streaming
 @POST("gists/public")
 Call<ResponseBody> getStreamingBig(a);
Copy the code
  • Streaming indicates that the data in the response body will be returned as a stream. Used when large data is returned, this annotation is especially useful when downloading large files

We need to add the @Streaming annotation when using large files to download

8) @multipart, @Part, @partmap

@Multipart
@POST("user/followers")
Call<ResponseBody> getPartData(@Part("name") RequestBody name, @Part MultipartBody.Part file);
Copy the code
  • @multipart indicates that the request entity is a form that supports file uploading. It can be used together with @Part and @PartMap for file uploading
  • @Part is used for form fields and is suitable for file upload. @Part supports three types: RequestBody, MultipartBody.Part, and any type
  • @PartMap is used for multi-file uploads, similar to the use of @fieldMap and @QueryMap

@multipart = @multipart; @multipart = @multipart; @multipart = @multipart;

// Declaration type, here is the literal type
 MediaType textType = MediaType.parse("text/plain");
// Create a RequestBody based on the declared type, which translates to a RequestBody object
RequestBody name = RequestBody.create(textType, "Here's the text you need to write: Liu Yifei");

// Create a file
File file = new File("File path");
if(! file.exists()) { file.mkdir(); }// Convert the file to a RequestBody object
// When you need to upload a file in a form, you need to use the format multipart/form-data
RequestBody imgBody = RequestBody.create(MediaType.parse("image/png"), file);
// Convert the file to multipartbody.part
// First parameter: upload file key; Second argument: filename; The third argument: the RequestBody object
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), imgBody);

Call<ResponseBody> partDataCall = retrofit.create(Api.class).getPartData(name, filePart);
Copy the code

Declare the type, then convert it to a RequestBody object based on the type, return the RequestBody or convert it to multipartBody. Part, and use the format multipart/form-data when a file needs to be uploaded in the form.

The use of @partMap is similar to the use of @fieldMap and @QueryMap for multi-file uploads. Let’s look directly at the code:

 @Multipart
 @POST("user/followers")
 Call<ResponseBody> getPartMapData(@PartMap Map<String, MultipartBody.Part> map);

Copy the code
    File file1 = new File("File path");
    File file2 = new File("File path");
        if(! file1.exists()) { file1.mkdir(); }if(! file2.exists()) { file2.mkdir(); } RequestBody requestBody1 = RequestBody.create(MediaType.parse("image/png"), file1);
    RequestBody requestBody2 = RequestBody.create(MediaType.parse("image/png"), file2);
    MultipartBody.Part filePart1 = MultipartBody.Part.createFormData("file1", file1.getName(), requestBody1);
    MultipartBody.Part filePart2 = MultipartBody.Part.createFormData("file2", file2.getName(), requestBody2);

    Map<String,MultipartBody.Part> mapPart = new HashMap<>();
        mapPart.put("file1",filePart1);
        mapPart.put("file2",filePart2);

    Call<ResponseBody> partMapDataCall = retrofit.create(Api.class).getPartMapData(mapPart);
Copy the code

(@partMap Map

Map) multipartbody. Part can be RequestBody, String, multipartbody. Part, etc. Can be replaced according to individual needs, here is not to say clearly.
,>

2. Simple use of Retrofit in projects (GET requests)

To formally use RetroFIT in a project, the following steps are required:

1) Add network permissions to the manifest file

Retrofit is a web request framework, and you definitely have to add Internet permissions to the Androidmanifest.xml file

<uses-permission android:name="android.permission.INTERNET"/>
Copy the code

2) Add retrofit’s dependency libraries

Add the Retrofit dependency library to the build.gradle file. You don’t need to add the OKHTTP library because Retrofit already encapsulates okHTTP

implementation 'com. Squareup. Retrofit2: retrofit: 2.5.0'
Copy the code

3) Create a class that accepts data from the server

In the formal request network data, the external nested part of the returned data is the same, with the status code, status information, and entity data returned together. We can encapsulate it into a unified data callback class.

public class Data<T> {
    private int code;
    private String message;
    private T data;

    public int getCode(a) {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage(a) {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData(a) {
        return data;
    }

    public void setData(T data) {
        this.data = data; }}Copy the code

4) Create classes that describe network interfaces

This class is Retrofit’s interface class that abstracts okHTTP requests into Java, describes and configates network request parameters with annotations, and encapsulates Url addresses and network data requests

public interface Api {
    / / get request
    @GET("api/rand.music")
    Call<Data<Info>> getJsonData(@Query("sort") String sort, @Query("format") String format);
}
Copy the code

In parentheses is the address of the request (part of the Url). The return type is Call<*>. * indicates the class that received the Data. Then there are the parameter types and parameter fields, which are essentially key-value pairs.

5) Create Retrofit instances

    // Build a Retrofit instance
    Retrofit retrofit = new Retrofit.Builder()
            // Set the network request BaseUrl address
            .baseUrl("https://api.uomg.com/")
            // Set the data parser
            .addConverterFactory(GsonConverterFactory.create())
            .build();
Copy the code

Build the Retrofit instance object with new Retrofit.Builder().buile() and set the baseUrl address. Retrofit divides the URL of the network request into two parts: When you create an instance of Retrofit through the.baseurl () setting,

.baseUrl("https://api.uomg.com/")
Copy the code

This address will be concatenated with the address above the method request annotation. The baseUrl address must end with a/or an error will be reported.

Part 2: Annotation Settings in the network request interface, which is the string annotated by GET in the above APi:

 @GET("api/rand.music")
Copy the code

The complete address is api.uomg.com/api/rand.mu… , and then set up the data interpreter with addConverterFactory, where the Gson interpreter is added. This is so that json results from the interface will be automatically parsed into json object acceptance classes that match the defined fields and types. In Retrofit 2.0, there is no Converter, so you need to create a Converter, otherwise Retrofit will only accept string results. Finally, you need to parse it yourself.

Add Converter dependencies to build.gradle:

implementation 'com. Squareup. Retrofit2: converter - gson: 2.0.2'
Copy the code

Retrofit supports multiple data parsing that requires adding dependencies to Gradle:

Data parser Gradle rely on
Gson Com. Squareup. Retrofit2: converter – gson: 2.0.2
Jackson Com. Squareup. Retrofit2: converter – Jackson: 2.0.2
Simple XML Com. Squareup. Retrofit2: converter – simplexml: 2.0.2
Protobuf Com. Squareup. Retrofit2: converter – protobuf: 2.0.2
Moshi Com. Squareup. Retrofit2: converter – moshi: 2.0.2
Wire Com. Squareup. Retrofit2: converter – wire: 2.0.2
Scalars Com. Squareup. Retrofit2: converter – scalars: 2.0.2

6) Create network request interface instance

// Create a network request interface object instance
Api api = mRetrofit.create(Api.class);
// Encapsulate the send request
Call<Data<Info>> dataCall = api.getJsonData("New Songs"."json");
Copy the code

Call the Retrofit instance object create() method, pass in the network interface class, get the interface object instance, and call the methods in the interface class.

7) Sending network requests (synchronous/asynchronous)

// Asynchronous request
dataCall.enqueue(new Callback<Data<Info>>() {
    // Requested a successful callback
     @Override
     public void onResponse(Call<Data<Info>> call, Response<Data<Info>> response) {}// Request failed callback
     @Override
     public void onFailure(Call<Data<Info>> call, Throwable t) {}});Copy the code
// Synchronize the request
Response<Data<Info>> data= dataCall.execute();
Copy the code

8) Process the returned data

 dataCall.enqueue(new Callback<Data<Info>>() {
     @Override
     public void onResponse(Call<Data<Info>> call, Response<Data<Info>> response) {
           Toast.makeText(MainActivity.this."Get callback successful: asynchronous execution", Toast.LENGTH_SHORT).show();
           Data<Info> body = response.body();
           if (body == null) return;
           Info info = body.getData();
           if (info == null) return;
           mTextView.setText("Data returned:" + "\n\n" + info.getName() + "\n" + info.getPicurl());
     }

      @Override
      public void onFailure(Call<Data<Info>> call, Throwable t) {
         Log.e(TAG, "Callback failed:" + t.getMessage() + "," + t.toString());
          Toast.makeText(MainActivity.this."Callback failed", Toast.LENGTH_SHORT).show(); }});Copy the code

The data returned asynchronously is processed and the network load is complete. The get request address is: https://api.uomg.com/api/rand.music?sort=%E6%96%B0%E6%AD%8C%E6%A6%9C&format=json

The effect is shown below:

Click the Execute GET request button, the code executes the GET request, and some time later returns the result of the request.

3. Simple use of POST requests

Instead of repeating the steps in the get request example above, let’s look at different parts:

1) Create network request interface:

public interface Api {
   // Post requests, @formurlencoded annotations if any parameters are needed, that is, with @field
    @FormUrlEncoded
    @POST("api/comments.163")
    Call<Object> postDataCall(@Field("format") String format);
}
Copy the code

2) Call the network request interface instance and process the returned data:

         // Step 4: Create a Retrofit object
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.uomg.com/") // Set the network request baseUrl
                .addConverterFactory(GsonConverterFactory.create()) // Set to use Gson parsing
                .build();

        // Step 5: Create the network request interface instance
        Api request = retrofit.create(Api.class);

        // Step 6: Encapsulate the send request:
        Call<Translation> call = request.postDataCall("JSON");

        // Step 7: Send network request (asynchronous)
        call.enqueue(new Callback<Translation>() {
            // Callback if the request succeeds
            @Override
            public void onResponse(Call<Translation> call, Response<Translation> response) {
                // Step 8: Request processing, output results
                Object body = response.body();
                if (body == null) return;
                mTextView.setText("Data returned:" + "\n\n" + response.body().toString());
                Toast.makeText(MainActivity.this."Post callback successful: asynchronous execution", Toast.LENGTH_SHORT).show();
            }

            // Callback if the request fails
            @Override
            public void onFailure(Call<Translation> call, Throwable throwable) {
                Log.e(TAG, "Post callback failed:" + throwable.getMessage() + "," + throwable.toString());
                Toast.makeText(MainActivity.this."Post callback failed", Toast.LENGTH_SHORT).show(); }});Copy the code

The data returned asynchronously is processed and the network load is complete. The request address and parameters for POST are printed as follows:

The data printing effect is as follows:

Click the Execute POST request button, the code executes the POST request, and some time later returns the result of the request.

  • The source address

Pay attention and don’t get lost

Well, everyone, that’s all for this article. Thank you so much for reading this article. The people here are talented. Thank you for your support and recognition, your praise is the biggest motivation for my creation, we will see you in the next article!

If there are any mistakes in this blog, please comment, thank you very much!

Reference links:

  • Retrofit2,
  • Network loading framework – Retrofit
  • This is a very detailed Retrofit 2.0 tutorial (with examples)
  • RxJava+Retrofit+OkHttp

I hope we can be friends inGithub,The Denver nuggetsShare knowledge together and encourage each other!