I will write the following series of articles to summarize Retrofit’s explanation:

  • Basic use of Get and Post requests
  • To upload pictures
  • The download file
  • Adding interceptors
  • . (Used in conjunction with RxJava, RxJava+Retrofit+OkHttp simple encapsulation, unified error handling)

Before the explanation, I had to be a model customer of a website. Before learning Retrofit, all kinds of network requests had to have an interface to access if I wanted to learn. The Get request was ok, but when I met the Post request, I didn’t know what I was sending. So the way Retrofit has been studied is either by looking for an existing API, or by just playing around with it and not doing it, but with this website you can write your own interface and go to it and test it and see if Retrofit is working properly.

See how Retrofit works in this article

1. Basic use of Retrofit

1.1 Adding a Dependency

//Retrofit
implementation 'com. Squareup. Retrofit2: retrofit: 2.5.0'
//Gson converter
implementation 'com. Squareup. Retrofit2: converter - gson: 2.5.0'
Copy the code

The second dependency is focused on parsing Json data.

1.2 Implementation Procedure

  • Create the interface for the network request
  • Create a Retrofit instance
  • Create an instance of the network request interface
  • Sending network Requests

As with the official website, you can look at the code described on the official website, which is the steps written above

  • public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);
    }
    Copy the code
  • Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
    Copy the code
  • GitHubService service = retrofit.create(GitHubService.class);
    Copy the code
  • Call<List<Repo>> repos = service.listRepos("octocat");
    Copy the code

1.3 Implementation

I’m going to give you a specific example, just to familiarize yourself with Retrofit for those of you who haven’t used Retrofit, right

1.3.1 Creating an Interface for Network Requests

public interface GetApi {

    /** * Get user information *@return
     * @QueryNote * /
    @GET("getUserInfo")
    Call<UserInfo> getUserInfo(@Query("id") String userId);

}
Copy the code

Forget what the @Query annotation is, we’ll explain it in more detail below.

UserInfo is the data Bean class from which we get the returned data

1.3.2 Creating a Retrofit instance

private Retrofit retrofit;
retrofit = new Retrofit.Builder()
    .baseUrl("http://mock-api.com/2vKVbXK8.mock/")
    .addConverterFactory(GsonConverterFactory.create()) // Parse the returned Json data
    .build();
Copy the code

BaseUrl:

Here baseUrl is the base address of the Url we’re accessing, plus the getUserInfo in @get (“getUserInfo”) is the actual address we’re accessing, and since we’re using @query (” ID “), the final address is

http://mock-api.com/2vKVbXK8.mock/getUserInfo?id=userid, here the userid incoming parameters for himself.

Note: baseUrl must end with /!!

AddConverterFactory:

Plus the addConverterFactory (GsonConverterFactory. The create (), fixed, will return the Json data direct analytical data Bean class for us

1.3.3 Creating an Instance of the Network Request Interface

private GetApi getApi;
getApi = retrofit.create(GetApi.class);
Copy the code

1.3.4 Sending network Requests

getApi.getUserInfo(userid).enqueue(new Callback<UserInfo>() {
    @Override
    public void onResponse(Call<UserInfo> call, Response<UserInfo> response) {
        if(response ! =null&& response.body() ! =null) {
            // Here is the information obtainedUserInfo userInfo = response.body(); }}@Override
    public void onFailure(Call<UserInfo> call, Throwable t) {
        Log.i(TAG, "onFailure: "+ t); }});Copy the code

Do not forget to apply for network permission when using, you may encounter the following problems:

CLEARTEXT communication to mock-api.com not permitted by network security policy

This is because Android P does not allow plaintext access and the previous mock address starts with HTTP. The solution is to add the following code to the application in AndroidManifest:

android:usesCleartextTraffic="true"
Copy the code

That’s a basic Retrofit web request, so let’s take a look at the main annotations in the Retrofit Web request interface.

2. Get request

BaseUrl is: http://mock-api.com/2vKVbXK8.mock/

2.1 @ Query

Access to the address

http:/ / mock-api.com/2vKVbXK8.mock/api/getUserInfo?id=1234 / / 1234 for the coming of parameters
Copy the code

The instance

@GET("api/getUserInfo")
Call<UserInfo> getUserInfo(@Query("id") String userId);
Copy the code
public class UserInfo { 
    private String userId;
    private String userName;
    private String describe;
}
Copy the code

When we want to access the address: baseUrl+getUserInfo? Id = 1234 to? To concatenate a parameter in this format, use the @query annotation, which adds? To getUserInfo And concatenates the URL in the form of the userId parameter passed in id=

2.2 @ QueryMap

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/getArticalInfo?id=405&page=1
Copy the code

The instance

@GET("api/getArticalInfo")
Call<ArticalInfo> getArticalInfo(@QueryMap Map<String, String> params);
Copy the code
public class ArticalInfo {   
    private String articalName;
    private String url;
}
Copy the code

When is the address to be accessed through? The @QueryMap annotation is used when the form concatenates multiple parameters

Specific use:

Map<String, String> params = new HashMap<>();
params.put("id"."405");
params.put("page"."1");

getApi.getArticalInfo(params).enqueue(new Callback<ArticalInfo>() {
    @Override
    public void onResponse(Call<ArticalInfo> call, Response<ArticalInfo> response) {
        if(response ! =null&& response.body() ! =null) {
            Log.i(TAG, "onRespons:"+ response.body().toString()); }}@Override
    public void onFailure(Call<ArticalInfo> call, Throwable t) {
        Log.i(TAG, "onFailure: "+ t); }});Copy the code

2.3 @ Path

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/getDynamicInfo/1/data
http://mock-api.com/2vKVbXK8.mock/api/getDynamicInfo/2/data
Copy the code

The instance

@GET("api/getDynamicInfo/{param}/data")
Call<ResponseBody> getDynamicInfo(@Path("param")int param);
Copy the code

The @path annotation is used when the address to be accessed is dynamically concatenated from an argument. In the example above, param is the argument passed in when the method is called later

getApi.getDynamicInfo(param).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 	{
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);           
        } catch(IOException e) { e.printStackTrace(); }}@Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: "+ t); }});Copy the code

If you look carefully, you’ll notice that this is different from the Call

, which is called ResponseBody, which is used when the specific data returned is not a Bean class that we know about, so we can retrieve the returned data as a string.

2.4 @ Url

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/getDynamicUrlData
Copy the code

The instance

@GET
Call<ResponseBody> getDynamicUrl(@Url String url);
Copy the code

The @URL annotation is used when the address to be accessed dynamically changes not just a few parameters, but the entire address, even the base class address

The specific use

String url = "http://mock-api.com/2vKVbXK8.mock/api/getDynamicUrlData"
    
getApi.getDynamicUrl(url).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 	{
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);

        } catch(IOException e) { e.printStackTrace(); }}@Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: "+ t); }});Copy the code

So this annotation is very handy, all the links that the above annotation visits can be accessed through the full Url passed in through this annotation.

Pay attention to

Although the final address is independent of the original baseUrl, the baseUrl must start with http:// or https:// and be followed by at least one letter or something else, otherwise an error will be reported.

http://				
Copy the code

Invalid URL host: “” error

http://a
Copy the code

When I actually test this, I can write anything in this A, but I can write anything that doesn’t end in a PI, right

2.5 @ Headers (” “)

Statically add header information: add a single header or add multiple headers

Internally fill in the content as key:value via the @headers (“”) annotation

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/staticHeaderInfo
Copy the code

The instance

Add a single header statically

@Headers("Version: 1.1")
@GET("api/staticHeaderInfo")
Call<GetBean> getStaticHeadersInfo(a);
Copy the code

Add multiple headers statically

@Headers({"Version: 1.1"."type:android"})
@GET("api/staticHeadersInfo")
Call<GetBean> getStaticMoreHeadersInfo(a);
Copy the code

Die guest background

2.6 @ the Header

Dynamically add single header information

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/dynamicHeadersInfo
Copy the code

The instance

@GET("api/dynamicHeadersInfo")
Call<ResponseBody> getDynamicHeaderInfo(@Header("version") String version);
Copy the code
getApi.getDynamicHeaderInfo(1.1.1 "").enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 	{}@Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {}});Copy the code

Die guest background

You can see that we did add version=1.1.1 to the header when we visited.

2.7 @ HeaderMap

Dynamically add multiple header information

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/dynamicHeadersInfo
Copy the code

The instance

@GET("api/dynamicHeadersInfo")
Call<ResponseBody> getDynamicHeadersInfo(@HeaderMap Map<String, String> headers);
Copy the code
Map<String, String> headers = new HashMap<>();
headers.put("version".2.2.2 "");
headers.put("type"."Android");

getApi.getDynamicHeadersInfo(headers).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 	{}@Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {}}); }Copy the code

Die guest background

You can see that the header information is already loaded in the header when we access it

3. A Post request

In contrast to annotations in Get requests, annotations in Post requests are easy to remember.

@ Field corresponding @ Query

@ @ QueryMap FieldMap

@ Body corresponding @ Url

Pay attention to

Try not to use @Query and @QueryMap in Post requests because the parameters passed in are unsecurely concatenated to the URL, whereas @field and @fieldMap are written to the Body.

3.1 @ FormUrlEncoded

@Formurlencoded is used to decorate @field annotations and @fieldMap annotations, which will automatically change the type of the request parameters to

application/x-www-form-urlencoded

3.2 @ Field

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/fieldParam
Copy the code

The instance

@FormUrlEncoded
@POST("api/fieldParam")
Call<ResponseBody> postFieldFun(@Field("key") String key);
Copy the code

Remember to add @formurlencoded, otherwise the following error will be reported:

@Field parameters can only be used with form encoding
Copy the code

use

private PostApi postApi;
postApi = retrofit.create(PostApi.class);

postApi.postFieldFun("myfittinglife").enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 	{
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);           
        } catch(IOException e) { e.printStackTrace(); }}@Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: "+ t); }});Copy the code

Die guest background

You can see that the parameters we added with the @field annotation are written in the body rather than concatenated directly after the Url

Here we are matching according to the rules we set up, of course we can also choose text or other ways to match.

3.3 @ FieldMap

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/fieldMapParam
Copy the code

The instance

@FormUrlEncoded
@POST("api/fieldMapParam")
Call<ResponseBody> postFildMapFun(@FieldMap Map<String, String> params);
Copy the code

@fieldMap when passing multiple arguments of the same type

use

Map<String, String> params = new HashMap<>();
params.put("key"."myfittinglife");
params.put("password"."123456");

postApi.postFildMapFun(params).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 	{
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);
        } catch(IOException e) { e.printStackTrace(); }}@Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: "+ t); }});Copy the code

Die guest background

You can see the two parameters we passed inside the body

3.4 @ Body

3.3 You can see that the @fieldMap annotation is suitable for passing multiple parameters of the same type. It is not possible to write multiple @fields if there are multiple different types of passing

Call<ResponseBody> postFieldFun(@Field("key") String key,@Field("num")int num);

It’s a lot more complicated if you want more than one type, so here we can just pass in an object with the @body annotation, and it can have multiple types of data in it.

Access to the address

http://mock-api.com/2vKVbXK8.mock/api/bodyParam
Copy the code

The instance

@POST("api/bodyParam")
Call<ResponseBody> postBodyFun(@Body PostBodyBean postBodyBean);
Copy the code
public class PostBodyBean {
    private String key;
    private int num;
    private boolean isTrue;
}
Copy the code

use

PostBodyBean postBodyBean = new PostBodyBean("myfittinglife".1.true);
postApi.postBodyFun(postBodyBean).enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) 	{
        try {
            String str = new String(response.body().bytes());
            Log.i(TAG, "onResponse: " + str);
        } catch(IOException e) { e.printStackTrace(); }}@Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.i(TAG, "onFailure: "+ t); }});Copy the code

Die guest background

You can see the Body that we passed

Pay attention to

Using the @ Body annotation must be created and Retrofit. AddConverterFactory (GsonConverterFactory. The create ()), the purpose is to convert objects to json string, otherwise it will report the following error

Unable to create @Body converter for class PostBodyBean
Copy the code

3.5 @ Part / @ PartMap

These two comments are related to file uploads and will be explained in more detail in a later article.

4. Pay attention to

  • To access the HTTP address beginning, remember to add android application in the AndroidManifest: usesCleartextTraffic = “true”

  • GET requests cannot use the @body annotation

  • BaseUrl urls must end with a slash

  • @ Body annotation must add addConverterFactory (GsonConverterFactory. The create ())

  • When the @get or @post annotation’s URL is a full path (which may not be the same field as baseUrl), the annotation’s URL field is used directly.

  • When the @path annotation is used, the Path corresponding to Path cannot contain /. Otherwise, the Path will be converted to %2F, and the following error is reported. Use @URL when you want to dynamically concatenate multi-section urls.

    Attempt to invoke virtual method 'byte[] okhttp3.ResponseBody.bytes()' on a null object reference
    Copy the code

5. To summarize

That’s a basic introduction to Retrofit’s annotations, which can be found on Github.

For ease of observation, this article uses only one annotation to establish the interface. In practice, multiple annotations can be used together, as shown below:

@GET("api/{param}/getUserInfo")
Call<UserInfo> getUserInfo(@Path("params") String param, @Query("id") String userId);
Copy the code

The specific combination depends on the URL provided by the actual project. The above is all content, limited ability, wrong place also hope to point out, if there is help also hope to point out a start, see the next article.

6. Refer to the article

Retrofit’s official Github address

Retrofit website

Talk about annotations in Retrofit