Retrofit源码流程解析(二)
上一篇讲了Retrofit的请求流程,对框架的大致调用过程做了了解,地址在这里Retrofit源码流程解析(一),这一篇打算讲解具体调用Okhttp3的过程,以及数据请求完成对数据的解析过程。这一过程都集中在OkHttpCall这个类中,更将详细的话还是通过它回调到其它类中。接下来还是结合具体源码来讲解。我们知道Retrofit有execute同步和enqueue异步两种请求方式,分别都会调用到OkHttp3这两个方法中,那么我们首先看第一个方法。
execute
@Override public Response<T> execute() throws IOException { okhttp3.Call call; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; if (creationFailure != null) { if (creationFailure instanceof IOException) { throw (IOException) creationFailure; } else if (creationFailure instanceof RuntimeException) { throw (RuntimeException) creationFailure; } else { throw (Error) creationFailure; } } call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); //1 } catch (IOException | RuntimeException | Error e) { throwIfFatal(e); // Do not assign a fatal error to creationFailure. creationFailure = e; throw e; } } } if (canceled) { call.cancel(); } return parseResponse(call.execute()); //2 }
这段代码只用看标记处,其它基本都只是异常和条件的判断,先看第一处,通过返回值可以知道是创建请求对象call的,看它的具体方法
private okhttp3.Call createRawCall() throws IOException { Request request = serviceMethod.toRequest(args); okhttp3.Call call = serviceMethod.callFactory.newCall(request); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }
在这个方法里面首先通过toRequest创建一个Request对象,它是OkHttp3里面的对象,是用来封装网络请求参数的,它的具体实现在ServiceMethod中。
/** Builds an HTTP request from method arguments. */ Request toRequest(@Nullable Object... args) throws IOException { RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types. ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers; int argumentCount = args != null ? args.length : 0; if (argumentCount != handlers.length) { throw new IllegalArgumentException("Argument count (" + argumentCount + ") doesn't match expected count (" + handlers.length + ")"); } for (int p = 0; p < argumentCount; p++) { handlers[p].apply(requestBuilder, args[p]); } return requestBuilder.build(); }
可以看见就是对创建Request过程的封装,首先实例化一个RequestBuilder对象,里面封装了请求方法,url,以及其它表单相关参数。接着调用ParameterHandler的apply方法完成参数的设置,来看下ParameterHandler是在哪里赋值初始化的。这个属性的赋值是在ServiceMethod的build方法里面。
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); //1 }
parameterHandlers是个数组,它的长度是参数注解个数,parameterHandlers的赋值是在标注处。调用的parseParameter方法,里面最终会调用parseParameterAnnotation方法,这个方法是根据不同的注解参数实例化ParameterHandler对象。由于这个方法太长了,我只对其中一种情况做解释,其余的可以自行查看, 就举例annotation为path的情况
if (annotation instanceof Path) { if (gotQuery) { throw parameterError(p, "A @Path parameter must not come after a @Query."); } if (gotUrl) { throw parameterError(p, "@Path parameters may not be used with @Url."); } if (relativeUrl == null) { throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod); } gotPath = true; Path path = (Path) annotation; String name = path.value(); validatePathName(p, name); Converter<?, String> converter = retrofit.stringConverter(type, annotations); //1 return new ParameterHandler.Path<>(name, converter, path.encoded()); //2 }
最后一句实例化了一个ParameterHandler.Path对象,并且传了一个converter,这个converter是什么了,它的作用是将返回的response做相应的转化对象,我们可以通过converter将response直接转化为string返回,也可以解析成一个javabean,然后提供给用户直接使用,不需要手动解析,甚至可以定制化自己的converter对象。那么我们查看这个stringConverter的具体实现,它的实现在Retrofit中,看下具体做了那些操作
/** * Returns a {@link Converter} for {@code type} to {@link String} from the available * {@linkplain #converterFactories() factories}. */ public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) { checkNotNull(type, "type == null"); checkNotNull(annotations, "annotations == null"); for (int i = 0, count = converterFactories.size(); i < count; i++) { Converter<?, String> converter = converterFactories.get(i).stringConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<T, String>) converter; } } // Nothing matched. Resort to default converter which just calls toString(). //noinspection unchecked return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE; }
首先从设置的converterFactories里面去查找,如果有就返回符合的converter,没有符合条件的就返回
BuiltInConverters.ToStringConverter.INSTANCE
如果去里面查看convert方法,可以看见就是调用了toString()方法返回了一个String字符串。
接下来看下
new ParameterHandler.Path<>(name, converter, path.encoded())
做了什么操作
static final class Path<T> extends ParameterHandler<T> { private final String name; private final Converter<T, String> valueConverter; private final boolean encoded; Path(String name, Converter<T, String> valueConverter, boolean encoded) { this.name = checkNotNull(name, "name == null"); this.valueConverter = valueConverter; this.encoded = encoded; } @Override void apply(RequestBuilder builder, @Nullable T value) throws IOException { if (value == null) { throw new IllegalArgumentException( "Path parameter \"" + name + "\" value must not be null."); } builder.addPathParam(name, valueConverter.convert(value), encoded); } }
这段代码中,内部类Path继承了抽象类ParameterHandler,并实现了apply方法。同时可以查看其它的继承它的内部类
它们都是不同的方法注解对应的具体返回。
那么,我们继续回到ServiceMethod的toRequest方法,里面有这么一段
for (int p = 0; p < argumentCount; p++) { handlers[p].apply(requestBuilder, args[p]); }在这段代码中调用了ParameterHandler的apply方法,给requestBuilder设置args参数值,其实具体查看Path的apply方法,就是做了一个参数替换,将name替换成对应的value。到了这里可以知道,每一个参数注解对应一个ParameterHandler的具体实现,它的作用就是封装了参数name,value已经对应的处理方法。到了这里toRequest方法也就解释完毕了。
继续回到createRawCall方法
private okhttp3.Call createRawCall() throws IOException { Request request = serviceMethod.toRequest(args); okhttp3.Call call = serviceMethod.callFactory.newCall(request); //2 if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }
标注2处调用serviceMethod.callFactory.newCall方法,其实如果仔细看了Retrofit的builder方法,就可以知道callFactory的赋值是在这里,callFactory就是okhttpclient对象,它然后就去调用newCall,实际就是返回okhttp里面的call对象的实例,然后用call去做网络请求操作。
这部分完成了,接着继续看execute方法的最后一句
parseResponse(call.execute())
刚刚获取的call对象,然后去调用execute做同步请求,返回的response,然后传到parseResponse方法里面解析response
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 { T body = serviceMethod.toResponse(catchingBody); //1 return Response.success(body, rawResponse); //2 } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } }
这段代码只需要看标记处,首先会调用serviceMethod的toReponse解析response
/** Builds a method return value from an HTTP response body. */ R toResponse(ResponseBody body) throws IOException { return responseConverter.convert(body); }
这个responseConverter的赋值其实是调用retrofit的nextResponseBodyConverter方法
public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { checkNotNull(type, "type == null"); checkNotNull(annotations, "annotations == null"); 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; } } 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()); }
代码表示得很清楚了,会遍历converterFactories集合的responseBodyConverter方法,根据type和annotation匹配符合条件的converter然后去调用它的convert,最后将转换的结果回调给调用者。
到了这里,execute的流程就完毕了。接下来就是enqueue方法了。
enqueue
@Override public void enqueue(final Callback<T> callback) { checkNotNull(callback, "callback == null"); okhttp3.Call call; Throwable failure; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) throws IOException { Response<T> response; try { response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } callSuccess(response); } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callSuccess(Response<T> response) { try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } }); }
其实刚刚讲了execute方法,而enqueue方法大致逻辑基本一样,只不过一个是同步一个是异步操作,enqueue调用的是okhttp的enqueue方法,成功之后也是会调用parseResponse方法去解析response,将解析的结果回调给retrofit的Callback回调方法。由于okhttp的异步操作回调是子线程,所以切换线程的操作还是由Retrofit来完成,至于怎么切换的第一篇文章已经讲解了,这里就不做过多的赘述了。
总结
Retrofit源码的讲解也就告一段落了,至于还有什么补充的,后面有新体会时候再来讲解了,其实Retrofit的源码还算简单的,多看几遍还是容易懂的,并且里面的各种设计模式以及解耦操作很值得学习,有时间的话还是值得多研究的。