Android network request framework -- use of Retrofit

stay Android network request framework - Retrofit (dynamic agent mode) This section mainly introduces the use of Retrofit.

1. Advantages of retrofit
API is simple, annotation is highly decoupled, multiple parsers are supported, and RxJava is supported.

2. use
After introducing these advantages of Retrofit, let's see how its advantages are realized from the perspective of use.

(1) Before using, you need to do some configuration, add the Retrofit dependency library, OkHttp dependency library and data analysis library

implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.okhttp:okhttp:2.7.5'
implementation 'com.squareup.retrofit2:converter-gson:2.7.1'

(2) Create interface and set request parameters
First, we create an entity class, DataBean, which is generally created according to the returned data type. This is the same as the general data parsing, such as when using Gson or fastjson to parse JSON data, the created entity class is the same;

public interface UpdateService {
    @GET("getAppConfig.php")
    public Call<DataBean> update(
            //Internal is the requested parameter
            @Query("appid") String appid
    );
}

Then create an interface indicating the address we want to request and the parameters of the request.

Some commonly used parameter notes:

@GET get request
@POST post request
@Path Dynamic URL substitution
@Query Parameters to pass
@QueryMap Multiple parameters (possibly more than 10)
@Body Add entity class object

(3) Create Retrofit object, set data parser, execute network request and get response data

Retrofit retrofit = new Retrofit.Builder().baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create()).build();
        UpdateService updateService = retrofit.create(UpdateService.class);
        Call<DataBean> call = updateService.update("ceshiqianggeng777");
        call.enqueue(new Callback<DataBean>() {
            @Override
            public void onResponse(Call<DataBean> call, Response<DataBean> response) {
                //The request is successful, and the return is a response encapsulated as a DataBean
                String url = response.body().getUrl();
                Log.e("TAG","Url ===== "+url);
            }

            @Override
            public void onFailure(Call<DataBean> call, Throwable t) {
                //request was aborted
            }
        });

After running, the url field in the DataBean response has been obtained successfully.

2020-02-06 17:16:47.147 2407-2407/com.example.myapplication E/TAG: Url ===== https://andownload.yyguokang120.com/bxvip/androidapk/152caizy01.apk

Briefly summarize the comparison between the use of Retrofit and OkHttp:
(1) When using OkHttp to process data, the acquired data needs to be manually parsed. For example, JSON data needs to create entity classes based on JSON data, and then acquire data. Although it is not difficult, it also needs several steps. Retrofit is directly in Response, so it encapsulates entity classes into this Response, and no need to manually parse again.
(2) I didn't update the UI here. For example, when using OkHttp, the acquired data needs to be returned to the main thread to get the data and update the UI. But when using Retrofit, I don't need to update the UI directly in onResponse

 @Override
public void onResponse(Call<DataBean> call, Response<DataBean> response) {
       //The request is successful, and the return is a response encapsulated as a DataBean
       String url = response.body().getUrl();
       Log.e("TAG","Url ===== "+url);
       //Update UI directly here
   }

3. Dynamic configuration url
In a network request, the base uurl will not change, but the request parameters may change. Therefore, if the request parameters after @ GET are written dead in the interface class, it is not extensible. Therefore, you can use @ Path to dynamically configure the url

Suppose that my GET request may request this interface at present, and then there are other interfaces, then you can take the parameter "getAppConfig.php" as the field value of Path, and enclose it with {};

public interface UpdateService {
    @GET("{path}")
    public Call<DataBean> update(
            //Internal is the requested parameter
            @Path("path") String path,
            @Query("appid") String appid
    );
}

Compare it with the one just opened

public interface UpdateService {
    @GET("getAppConfig.php")
    public Call<DataBean> update(
            //Internal is the requested parameter
            @Query("appid") String appid
    );
}
 Call<DataBean> call = updateService.update("getAppConfig.php","ceshiqianggeng777");

In fact, both request the same url:
baseurl/getAppConfig.php?appid=ceshiqianggeng777

If you used OkHttp before, would you like to use Retrofit for the first time?

4. Custom type conversion

When using Retrofit, we used the data parser GsonConverterFactory, which is the internal source code of the parser:

public final class GsonConverterFactory extends Converter.Factory {
  /**
   * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
   * decoding from JSON (when no charset is specified by a header) will use UTF-8.
   */
  public static GsonConverterFactory create() {
    return create(new Gson());
  }

  /**
   * Create an instance using {@code gson} for conversion. Encoding to JSON and
   * decoding from JSON (when no charset is specified by a header) will use UTF-8.
   */
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
//This method is not used at present, because we do not use post request.
  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

This data parser, internally new Gson(), converts the data response, that is, the ResponseBody, into a JavaBean. This process is carried out in the responseBodyConverter method. After obtaining the current data type, a GsonResponseBodyConverter object is returned

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      T result = adapter.read(jsonReader);
      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonIOException("JSON document was not fully consumed.");
      }
      return result;
    } finally {
      value.close();
    }
  }
}

Among the methods of GsonResponseBodyConverter, there is a convert method. After obtaining the data flow of ResponseBody, use Gson to convert the data flow to a corresponding type of JavaBean.

This is also when we use Retrofit, when we get the response, we have encapsulated the response of JavaBean for us.

If in actual use, in addition to the use of Gson conversion, for example, we want to convert time type to String type data, then we can also customize the data parser.

public class DateConvertFactory extends Converter.Factory {
    //Convert time type to String type
    @Override
    public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        if(type == Date.class){
            //Go to type conversion
            return new DateConvert();
        }
        return super.stringConverter(type, annotations, retrofit);
    }

    private class DateConvert implements Converter<Date, String> {
        private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        @Override
        public String convert(Date value) throws IOException {
            return sdf.format(value);
        }
    }
    
    public static DateConvertFactory create(){
        return new DateConvertFactory();
    }
}

In fact, the idea of this custom data parser is the same as that of the Gson data parser. The GsonConverterFactory inherits from the Converter.Factory, and then inherits the parent class. In addition to rewriting toString, there are also

These are reflected in the Gson data parser.

In the user-defined data analysis, it also inherits Converter.Factory and rewrites the stringConverter method. This method can convert a type to String type. If it is judged to be Date type, type conversion will be performed.

Type conversion implements the converter < Date, String > interface, converts Date to String, and rewrites the convert method.

Well, the above is the simple use of Retrofit, and it will be updated in the future!

Published 13 original articles, won praise 1, visited 348
Private letter follow

Tags: Retrofit JSON OkHttp PHP

Posted on Thu, 06 Feb 2020 08:43:19 -0500 by pkellum