Retrofit2.0之所以然-源码解读
- 源码解读
- 小结
源码解读
上节已经列出可以在项目中实操的retrofit使用方式,本节看一下核心的源码,通过对源码的认识,可以更了解其机制。
retrofit使用的是目前比较流行的流式编程。Retrofit中通过内部类Builder构建自身对象。
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//没有设置客户端的话,默认使用OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//适配工厂集合,一下两下解析不清,不添加的话,默认使用DefaultCallAdapterFactory对象,
//正常也使用默认,无需重新改工厂类
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
//这个是转换工厂,将响应的结果通过设置的转换工厂转换成对应的结果
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
Builder中通过build()来实例化Retrofit对象。可能会看到converterFactories 是一个集合,有么有兴奋的意淫,可以添加多个转换工厂?但是不幸的告诉您,可以添加,但是在大部分使用场景中默认使用的仅是第一个Converter.Factory。
Retrofit对象生成了,就该create()生成代理对象了。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//这里就是java为大家生成的动态代理对象
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, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
有了代理对象,代理对象自然可以调用自身的接口方法。在动态代理是个什么梗那章中已经介绍了执行接口方法实际上是执行动态代理中的invoke()方法。核心的为下面三个方法。
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
loadServiceMethod(method)是将定义的接口方法中的注释了,请求方式了,header头了等进行解析处理为ServiceMethod对象。其也是通过ServiceMethod的内部类Builder来构造的。
public ServiceMethod build() {
//这里是通过adapterFactories适配工厂的集合中的第一个适配工厂对象的CallAdapter。
//适配工厂不做太多介绍,能看该文的人的智商是无法重写适配工厂,
//重要的事情说三遍 使用过程中无需使用addCallAdapterFactory(factory)
callAdapter = createCallAdapter();
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?");
}
//这里就是场景响应数据的转换工厂
responseConverter = createResponseConverter();
//处理注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
//参数注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
下来来看看响应数据的转换吧
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
//skipPast=null
int start = converterFactories.indexOf(skipPast) + 1;
//start=0;
//这里用来遍历你添加的所有转换工厂选择出合适使用的
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;
}
}
StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
.append(type)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = converterFactories.size(); i < count; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
有人就纳闷这里明明遍历找最合适的,为啥本文前面强调只能添加一个转换工厂。
举个例子说吧!
响应的结果是不可转换为json串的字符串。那如果第一个转换工厂是GsonConverterFactory呢?他怎么知道这个格式是json,所以就默认使用GsonConverterFactory来处理,处理肯定报错。
什么GsonConverterFactory, SimpleXmlConverterFactory看其名知其用。
ScalarsConverterFactory?
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == String.class) {
return StringResponseBodyConverter.INSTANCE;
}
if (type == Boolean.class || type == boolean.class) {
return BooleanResponseBodyConverter.INSTANCE;
}
if (type == Byte.class || type == byte.class) {
return ByteResponseBodyConverter.INSTANCE;
}
if (type == Character.class || type == char.class) {
return CharacterResponseBodyConverter.INSTANCE;
}
if (type == Double.class || type == double.class) {
return DoubleResponseBodyConverter.INSTANCE;
}
if (type == Float.class || type == float.class) {
return FloatResponseBodyConverter.INSTANCE;
}
if (type == Integer.class || type == int.class) {
return IntegerResponseBodyConverter.INSTANCE;
}
if (type == Long.class || type == long.class) {
return LongResponseBodyConverter.INSTANCE;
}
if (type == Short.class || type == short.class) {
return ShortResponseBodyConverter.INSTANCE;
}
return null;
}
看到这可以晓得ScalarsConverterFactory到底可以处理什么数据格式了吧!
好了到这ServiceMethod对象也构建完成。然后到OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);这里其实构造的是OKhttpClient。这个serviceMethod.callAdapter.adapt(okHttpCall);呢?使用的默认的适配工厂DefaultCallAdapterFactory。
//放如啥返回啥,放入的是OkHttpCall实例,将该对象毫无保留的返回。
@Override public <R> Call<R> adapt(Call<R> call) {
return call;
}
也就是前面的动态代理对象调用其接口方法时,其实返回的是一个将接口方法解析的serviceMethod,以及OKhttpClient两者封装的OkHttpCall。
然后就到了我们的代码,就是
//同步或异步的调用了。
//同步请求
try {
Response<String> response = call.execute();
String body = response.body();
System.out.println(body);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
嗯!剩下的就是调用执行了,自行查看。就这样整个流程就串起来。
小结
无,无,无