这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」
上一篇已经分析道创建retrofit对象,这篇开始分析具体的请求网络请求的demo
使用Demo
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("xxxxxxxx")
.addConverterFactory(GsonConverterFactory.create())
.build();
OrderApi api = retrofit.create(OrderApi.class);
//对发送请求进行封装,同时生成最终的网络请求对象
Call<OrderInfo> xxxx = api.getOrderDetailByNo("xxxx");
retrofit.create(XXXX.class);
//通过动态生成的代理类,调用interfaces接口的方法实际上是通过调用InvocationHandler对象的invoke()来完成指定的功能
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
//使用动态代理技术拿到网络请求接口实例上的所有注解
return (T)
Proxy.newProxyInstance(
service.getClassLoader(), //动态生成接口的实现类
new Class<?>[] {service},//动态创建实例
new InvocationHandler() { //将代理类的实现交给 InvocationHandler类作为具体的实现
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
// 在 InvocationHandler类的invoke()实现中,除了执行真正的逻辑(如再次转发给真正的实现类对象),还可以进行一些有用的操作 :如统计执行时间、进行初始化和清理、对接口调用进行检查等。
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
使用动态代理的好处:
- 当
OrderApi对象调用getOrderDetailByNo(xxx)接口中方法时会进行拦截,调用都会集中转发到 InvocationHandler#invoke (),可集中进行处理 - 获得网络请求接口实例上的所有注解
- 更方便封装ServiceMethod
loadServiceMethod(method)方法讲解
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
//设置线程同步锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
// ServiceMethod类对象采用了单例模式进行创建。即创建ServiceMethod对象前,先看serviceMethodCache有没有缓存之前创建过的网络请求实例。若没缓存,则通过建造者模式创建 serviceMethod 对象
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
loadServiceMeyhod这个对象就是读取网络请求接口里的方法,并根据前面配置好的属性去配置ServiceMeyhod这个对象。
他会设置一个同步锁,设置一个同步锁就可以保证不同的线程去读取LinkedHashMap缓存的时候不会造成数据的不安全性。然后调用缓存当中的get方法,ServiceMeyhod这个类通过单例进行创建,也就是创建ServiceMeyhod这个对象之前,他会判断LinkedHashMap缓存当中是否有之前创建过的网络请求实例。如果没有缓存,他就设为空,调用Builder模式来创建一个ServiceMeyhod对象并进行缓存,就是调用他的put方法将他传入缓存当中。所以说,创建实例的缓存机制它的核心做法就是使用单例模式实现ServiceMeyhod的唯一性,然后这个ServiceMeyhod对象对应网络请求接口里的方法。
ServiceMethod生成实例的过程
abstract class ServiceMethod<T> {
//解析注解
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//解析注解获得请求的工厂对象
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
inal class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
private final Method method;
private final HttpUrl baseUrl;
final String httpMethod;
private final @Nullable String relativeUrl;
private final @Nullable Headers headers;
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
final boolean isKotlinSuspendFunction;
RequestFactory(Builder builder) {
method = builder.method;
baseUrl = builder.retrofit.baseUrl;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
headers = builder.headers;
contentType = builder.contentType;
hasBody = builder.hasBody;
isFormEncoded = builder.isFormEncoded;
isMultipart = builder.isMultipart;
parameterHandlers = builder.parameterHandlers;
isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
}
}
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(
method,
"'"+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}