在《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方法。
好了,以上就是Retrofit的简单的使用,后续还会继续更新!
那年1月26日那一天 发布了13 篇原创文章 · 获赞 3 · 访问量 351 私信 关注