Android网络请求框架------Retrofit的使用1

《Android网络请求框架-----Retrofit(动态代理模式)》中,简单介绍了一下Retrofit的底层实现原理,这一节主要介绍一下Retrofit的使用。

1.Retrofit的优点
API简单、使用注解高度解耦合、支持多种解析器、支持RxJava。

2.使用
在介绍了Retrofit的这些优点之后,从使用角度来看一下它的优点是如何具体实现的。

(1)在使用之前,需要做一些配置,加入Retrofit的依赖库、OkHttp的依赖库以及数据解析库

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)创建接口,设置请求参数
首先我们先创建一个实体类DataBean,一般是根据 返回的数据类型创建的,这个和一般数据解析是一样的,像在使用Gson或者fastjson解析JSON数据时,创建的实体类一致;

public interface UpdateService {
    @GET("getAppConfig.php")
    public Call<DataBean> update(
            //内部是请求的参数
            @Query("appid") String appid
    );
}

然后创建一个接口,注明我们想要请求的地址,以及请求的参数。

常用到的一些参数注解:

@GET get请求
@POST post请求
@Path 动态的URL代替
@Query 要传递的参数
@QueryMap 多参数(可能超过10个)
@Body 添加实体类对象

(3)创建Retrofit对象,设置数据解析器,执行网络请求,得到响应数据

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) {
                //请求成功,返回是一个封装为DataBean的响应
                String url = response.body().getUrl();
                Log.e("TAG","Url ===== "+url);
            }

            @Override
            public void onFailure(Call<DataBean> call, Throwable t) {
                //请求失败
            }
        });

运行后,已经成功获取DataBean响应中的url字段。

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

简单总结一下关于Retrofit的使用和OkHttp的对比:
(1)在使用OkHttp处理数据时,获取的数据需要去手动解析,像JSON数据,需要去根据JSON数据去创建实体类,然后获取数据,虽然不难,但是也需要几个步骤;Retrofit是直接在响应中,就将实体类封装到了这个Response中,不需要再去手动解析。
(2)我在这里没有去更新UI,像在使用OkHttp的时候,获取的数据需要去返回到主线程获取数据更新UI,但是在使用Retrofit不需要这样,直接在onResponse中更新UI

 @Override
public void onResponse(Call<DataBean> call, Response<DataBean> response) {
       //请求成功,返回是一个封装为DataBean的响应
       String url = response.body().getUrl();
       Log.e("TAG","Url ===== "+url);
       //可直接在此更新UI
   }

3.动态配置url
在网络请求中,base_url不会变,但是请求的参数可能会变,因此如果在接口类中,写死了@GET后边的请求参数,不具备扩展性,因此动态配置url,可以使用@Path

假设我这个GET请求可能目前请求的是这个接口,然后还有其他的接口,那么就可以把这个参数 “getAppConfig.php” 作为Path的字段值,然后用{ }括起来;

public interface UpdateService {
    @GET("{path}")
    public Call<DataBean> update(
            //内部是请求的参数
            @Path("path") String path,
            @Query("appid") String appid
    );
}

和刚开的做对比

public interface UpdateService {
    @GET("getAppConfig.php")
    public Call<DataBean> update(
            //内部是请求的参数
            @Query("appid") String appid
    );
}
 Call<DataBean> call = updateService.update("getAppConfig.php","ceshiqianggeng777");

其实两者请求的都是同一个url:
baseurl/getAppConfig.php?appid=ceshiqianggeng777

如果你之前使用的都是OkHttp,那么第一次使用Retrofit,有没有爱不释手的感觉呢?

4.自定义类型转换

在之前使用Retrofit的时候,使用到了数据解析器是GsonConverterFactory,这个解析器内部的源码:

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);
  }
//这个方法目前没用到,因为我们没有使用post请求。
  @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);
  }
}

这个数据解析器,在内部是new Gson(),然后在获取数据响应,也就是ResponseBody的时候,将其转换为JavaBean,这个过程是在responseBodyConverter方法中进行的,在获取了当前的数据类型之后,最终返回了一个GsonResponseBodyConverter对象

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();
    }
  }
}

GsonResponseBodyConverter方法当中,有一个convert方法,就是获取了ResponseBody的数据流后,利用Gson将这个数据流转换为对应类型的JavaBean。

这也是在我们使用Retrofit的时候,在获取响应的时候,已经为我们封装好了JavaBean的响应。

如果在实际的使用中,除了使用Gson转换之外,比如我们还想将时间类型转换为String类型的数据,那么我们也可以自定义数据解析器。

public class DateConvertFactory extends Converter.Factory {
    //将时间类型转换为String 类型
    @Override
    public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        if(type == Date.class){
            //就去进行类型转换
            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();
    }
}

其实这个自定义的数据解析器是跟Gson数据解析器的思想是一样的,GsonConverterFactory 是继承自Converter.Factory,然后继承这个父类,除了可以重写toString之外,还有
在这里插入图片描述
这些在Gson数据解析器中有体现。

在自定义的这个数据解析中,也是继承了Converter.Factory,重写了其中的stringConverter方法,这个方法可以将某个类型转换为String类型,如果判断是Date类型,那么就去进行类型转换。

类型转换是实现了Converter<Date, String>接口,将Date转换为String,重写了convert方法。

5.POST请求
在使用OkHttp的时候,如果使用post请求,那么需要创建一个请求体RequsetBody携带请求的数据,那么在Retrofit中,使用POST需要使用到注解参数@Field和@FormUrlEncoded。

public interface UpdateService {
    @GET("{path}")
    public Call<DataBean> update(
            //内部是请求的参数
            @Path("path") String path,
            @Query("appid") String appid
    );

    @POST("getAppConfig.php")
    @FormUrlEncoded
    public Call<DataBean> updateForPost(
            //请求的参数
            @Field("appid") String appid
    );
}

和GET请求相比,只是在请求时将 @Query换为了@Field;但是性质上就发生了很大的变化。在使用@Query时,是将请求的数据直接拼接在了url后面,@Field就相当于请求体的数据,先发送请求头,再发送请求体,更安全。

好了,以上就是Retrofit的简单的使用,后续还会继续更新!

发布了15 篇原创文章 · 获赞 5 · 访问量 628

猜你喜欢

转载自blog.csdn.net/qq_33235287/article/details/104197520