- APP使用retrofit接口层封装请求参数,之后有okhttp完成后续的请求操作。
- 在服务端返回数据之后,okhttp将原始的结果交给retrofit,retrofit根据用户的需求对结果进行解析。
一、用法:
上传下载的一些正确用法
请求过程7步骤:
1、添加gradle依赖,网络权限
2、创建接收数据的Bean
3、注解配置网络请求接口
4、创建Retrofit实例(builder模式)
5、创建具体的网络请求接口的实例
6、通过call发送网络请求(enqueue或execute)
7、处理返回的数据
二、retrofit代理设计模式
代理模式:给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用
静态代理:
抽象对象角色 interface
目标对象角色 也实现抽象角色
代理对象角色 也实现抽象角色
动态代理:通过反射在程序运行时创建的代理方式
1、jdk动态代理(必须要实现InvocationHandle接口)
2、cglib
实现InvocationHandle接口:
重写invoke方法的参数解释:
参数一:proxy,真实对象的代理
参数二:method,真实对象的某个方法
参数三:object[],真实对象的某个方法的所有参数
- 每个代理类的对象都会关联一个表示内部逻辑的InvocationHandle接口的实现。
- invoke方法的参数中可以获取参数
- invoke方法的返回值被返回给使用者
客户端调用的时候使用:
Proxy.newProxyInstance()方法
动态代理总结:
1、运行时实现动态关联
2、InvocationHandle接口和Proxy类
3、动态代理和静态代理最大的不同是运行时动态生成的。
三、网络通信流程8步骤和7个关键成员变量
网络通信八步:
1、创建retrofit实例
2、定义一个网络接口并添加注解
3、通过动态代理生成网络请求对象
4、通过网络请求适配器将网络请求对象进行平台适配
5、通过网络请求执行器(Call)发送网络请求
6、通过数据转换器(Gson)解析数据
7、通过回调执行器切换到主线程
8、在主线程处理返回结果
Retrofit源码:
Retrofit里面的7个关键成员变量:
//缓存网络请求
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
//生产OkHttpClient
final okhttp3.Call.Factory callFactory;
//基础URL
final HttpUrl baseUrl;
//数据转换器工厂集合(Gson,Jackson)
final List<Converter.Factory> converterFactories;
//网络请求适配器工厂集合(Rxjava)
final List<CallAdapter.Factory> adapterFactories;
//执行异步回调的执行器
final @Nullable Executor callbackExecutor;
//是否需要立即解析接口中的方法(动态代理中用到)
final boolean validateEagerly;
四、 builder构建者模式和Builder内部类
通过builder模式初始化retrofit的7个成员变量
1、配置平台对象
2、初始化retrofit的7个成员变量
build方法完成retrofit对象创建流程
五、RxjavaCallAdapterFactory内部构造与工作原理
//每次创建retrofit的时候要继承Factory这个抽象类,然后将继承之后的对象(RxJava2CallAdapterFactory),在构造retrofit的时候通过addCallAdapterFactory添加进去。
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {}
abstract class Factory {
//根据接口的返回类型,注解类型来得到我们实际需要的CallAdapter
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
//返回泛型参数的上限
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
//获取我们的原始的类型,跟我们判断选择不同的CallAdapter有关系
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
CallAdapter就是网络请求适配器,它的其中一个实现类就是RxJavaCallAdapter
如果要实现RxjavaCallAdapterFactory的配置
1、首先要实现CallAdapter.Factory抽象类,用来提供具体的适配逻辑
2、然后通过addCallAdapterFactory方法添加到Retrofit中(注册CallAdapter)
3、调用Factory.get方法来获取我们的CallAdapter
4、调用CallAdapter中的adapter方法,将我们Call请求转换成每一个平台所适用的类型。
retrofit请求网络基本流程:
获取到Call对象去执行请求,而retrofit调用这个call请求其实最终调用的是okhttp的call请求,只不过是封装了。
然后去服务端获取数据,获取到数据后调用converter(数据转换器)转换数据,
六、网络请求接口实例(ServiceMethod)解析
Retrofit请求流程:
Retrofit retrofit = new Retrofit.Builder().baseUrl("")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
Apis apis = retrofit.create(Apis.class);
Call<HttpResponse<List<Coin>>> call = apis.getCoinList(null);
call.enqueue(new retrofit2.Callback<HttpResponse<List<Coin>>>() {
@Override
public void onResponse(retrofit2.Call<HttpResponse<List<Coin>>> call, retrofit2.Response<HttpResponse<List<Coin>>> response) {
}
@Override
public void onFailure(retrofit2.Call<HttpResponse<List<Coin>>> call, Throwable t) {
}
});
接口定义好以后,是通过动态代理的方式把接口转换为实际请求,ServiceMethod对应的就是一个一个的接口方法。
create方法中:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
//1、会先判断是否是一个有效的method,判断是否有效会先执行loadServiceMethod方法
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//2、然后通过动态代理invoke方法中解析方法的注解(这个方法里面同样要执行loadServiceMethod方法)。
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//invoke方法中3行最经典的代码(也是retrofit中最核心的3行代码):
//retrofit的核心是这3行代码,3行代码的核心是ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
第一行核心代码解析(ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method)😉
//获得ServiceMethod,先从ServiceMethodCache中获取,如果缓存中没有,再重新构建,然后再把新获取的缓存到ServiceMethodCache中
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//如果没有缓存就重新创建一个ServiceMethod实例并缓存
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
下面具体解析:result = new ServiceMethod.Builder<>(this, method).build();
如何通过动态代理把我们定义的网络接口转换为ServiceMethod(实际请求对象)?
下面看看ServiceMethod类,有几个重要的变量,这几个变量包含了我们所有的网络请求的基本信息,它的初始化也是builder模式:
final class ServiceMethod<R, T> {
//OkHttp中的Call
final okhttp3.Call.Factory callFactory;
//网络请求适配器比如(RxjavaCallAdapter)
final CallAdapter<R, T> callAdapter;
private final HttpUrl baseUrl;
//数据转换器(GsonConverterAdapter)
private final Converter<ResponseBody, R> responseConverter;
//get post delete 等
private final String httpMethod;
//相对地址(和baseurl拼接在一起)
private final String relativeUrl;
//请求头
private final Headers headers;
//body
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
//最核心的,方法参数的处理器(方法和方法上面的注解都是它解析的)
private final ParameterHandler<?>[] parameterHandlers;
一、下面是builder模式内部类,注意3,4,5
Builder(Retrofit retrofit, Method method) {
//1、retrofit对象
this.retrofit = retrofit;
//2、请求方法名
this.method = method;
//3、网络请求接口里面的注解
this.methodAnnotations = method.getAnnotations();
//4、获取请求接口中参数的类型
this.parameterTypes = method.getGenericParameterTypes();
//5、获取注解里面的内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
}
二、build()方法
根据responseType和方法中的注解来解析整个需要的内容
public ServiceMethod build() {
//1、通过网络请求方法的返回值和注解类型,从retrofit对象中获取请求适配器。
callAdapter = createCallAdapter();
//2、根据网络请求接口方法的返回值和注解类型,从retrofit对象中获取这个请求适配器返回的数据类型
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//3、创建数据转换器
responseConverter = createResponseConverter();
//4、遍历注解,解析注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//5、遍历参数,解析参数
for (int p = 0; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
总结build()方法:
根据返回值类型和方法中的注解来从网络请求适配器工厂和数据转换器工厂分别获取到(request)请求适配器(callAdapter)和(response) 数据返回转换器(converter);
然后会根据参数注解来获取到参数;最后调用parseParameter解析结果中的参数。
其中里面的方法:
private CallAdapter<T, R> createCallAdapter() {
//网络接口方法返回的类型
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
//获取网络请求接口里面的注解
Annotation[] annotations = method.getAnnotations();
try {
//returnType:网络请求方法的返回值 ;annotations:注解类型
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
调用:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
调用:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
//遍历callAdapter的工厂集合寻找合适的工厂,然后通过get方法来获取CallAdapter,最后赋值给ServiceMethod的callAdapter
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
private Converter<ResponseBody, T> createResponseConverter() {
//获取接口中注解
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
调用:
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
调用:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
//遍历converter的工厂集合寻找合适的工厂,然后通过get方法来获取converter,最后赋值给ServiceMethod的converter
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
}
第二行核心代码解析OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
OkHttpCall实际调用的是okhttp3.Call rawCall,根据serviceMethod和参数创建Call对象,它就是封装了OkHttp中的Call对象
第三行核心代码解析 return serviceMethod.callAdapter.adapt(okHttpCall);
调用CallAdapter中的adapter方法,将我们Call请求转换成每一个平台所适用的类型。
到此,我们就把creat方法解析完毕了。
那么下面就看看create之后的请求了
Apis apis = retrofit.create(Apis.class);
retrofit2.Call<HttpResponse<List<Coin>>> call = apis.getCoinList(null);
call.enqueue(new retrofit2.Callback<HttpResponse<List<Coin>>>() {
@Override
public void onResponse(retrofit2.Call<HttpResponse<List<Coin>>> call, retrofit2.Response<HttpResponse<List<Coin>>> response) {
}
@Override
public void onFailure(retrofit2.Call<HttpResponse<List<Coin>>> call, Throwable t) {
}
});
同步请求和重要参数
retrofit请求:
retrofit帮我们封装了所有的请求,最终还是交给OkHttp去请求
同步:OkHttpCall.execute()
异步:OkHttpCall.enqueue()
retrofit中具体请求流程:
1、网络接口中的方法和参数利用ParameterHandle来进行解析
2、根据ServiceMethod对象创建一个OkHttp的request对象,有了这个对象才能进行实际的网络请求
(ServiceMethod这个对象很重要,所有需要缓存,它得到后就缓存在ServiceMethodCache中)
3、从ServiceMethod获取到request对象,通过OkHttpCall的底层:OkHttp库发送网络请求
4、通过converter解析数据
一句话总结:
对网络请求接口方法中的每个参数利用ParameterHandle来进行解析,第二步根据我们创建好的ServiceMethod对象创建Request对象,把Request对象交给OkHttp库来进行实际的网络请求发送,发送完后利用数据转换器converter将网络数据转为Java对象。
使用retrofit只需要将焦点放在接口的创建上,通过接口来配置请求即可,它内部的原理就是通过动态代理将接口中的方法转换为ServiceMethod对象,然后通过ServiceMethod对象获取到请求信息,最终网络底层的请求还是交给OkHttp请求的。
在retrofit中:final class OkHttpCall implements Call {},所以call.enqueue或call.execute最终调用的是OkHttpCall中的方法;OkHttpCall中实际使用了:okhttp3.Call
call.enqueue或call.execute最终都会调用createRawCall和parseResponse;
createRawCall得到okhttp3.Call对象,parseResponse解析数据返回
下面具体代码:
private okhttp3.Call createRawCall() throws IOException {
//调用ParameterHandle解析参数后创建Request对象
Request request = serviceMethod.toRequest(args);
//创建Call对象
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
回顾一下OkHttp库单独使用的步骤:
1、创建OkHttpClient和Request对象
2、将Request封装成Call对象( Call call = client.newCall(request))
3、调用call的enqueue(异步)或execute(同步)发送请求
Request toRequest(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
//解析注解中的请求入参
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
return requestBuilder.build();
}
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
//获取到响应码
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//将返回的数据通过convert(GsonConvert)转换为Java对象response。
T body = serviceMethod.toResponse(catchingBody);
//解析完后返回到success方法中
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
Retrofit的主要作用总结:
它精妙的地方是通过注解和接口把我们的http请求做了更好的封装,然后又通过动态代理来解析我们定义好的注解和接口方法和参数
拓展:retrofit采用的设计模式
1、构建者模式:复杂对象的表示和构建相分离
2、工厂模式:很好的拓展性,方便的添加不同平台的Factory,比如RxJavaCallAdapter,现在如果你想添加一个新的CallAdapter,那么你只需要extends CallAdapter.Factory即可。
3、外观模式:Retrofit相当于外观类,内部封装了我们所需要的请求子系统。当我们需要请求的时候是通过retrofit这个外观类来执行的。不需要知道内部是怎么做的。
客户端只和外观类交互,无需考虑内部实现,就是外观模式。
4、策略模式:动态配置CallAdapter和convert就是策略模式,根据不同的情况,使用不同的策略。
比如CallAdapter是抽象策略,RxjavaCallAdapter是具体策略
Convet是抽象策略,GsonConvertAdapter是具体策略
两者的区别:
工厂模式:生产不同的工厂对象
策略模式:这个不同对象的策略方法的具体实现
5、适配器模式:适配平台特性
6、动态代理模式
create方法的invoke方法,把接口和注解参数,转换为OkHttpCall。
7、观察者模式:当一个被观察者对象发生变化,它会通知观察它的对象。
call.enqueue异步请求的时候,采用了观察者模式
call是被观察者,Callback是观察者。