(借鉴自Android进阶之光)
我们从3个角度切入
1.Retrofit的创建过程
2.Call的创建过程
3.Call的enqueue方法
1.Retrofit的创建过程
网络接口
public interface LoginAPI { @GET("LoginServlet") Observable<JSONObject> login( @Query("user_name") String userName, @Query("user_password") String userPassword); }创建Retrofit
new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build()
Retrofit是通过建造者模式构建出来的,所以看一下Builder方法做了什么
public Builder() { this(Platform.get()); }再查看Platform.get()方法,最终会调用到下面的findPlatform()方法,这个方法的作用是检测你的运行平台。返回了运行平台之后,再根据不同的运行平台来提供不同的线程池。
class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get() { return PLATFORM; } private static Platform findPlatform() { try { Class.forName("android.os.Build"); if (Build.VERSION.SDK_INT != 0) { return new Android(); } } catch (ClassNotFoundException ignored) { } try { Class.forName("java.util.Optional"); return new Java8(); } catch (ClassNotFoundException ignored) { } try { Class.forName("org.robovm.apple.foundation.NSObject"); return new IOS(); } catch (ClassNotFoundException ignored) { } return new Platform(); }看一下build方法
public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } 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. 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); }最上面验证了一个常识,baseUrl不能为空。
接下来那个callFactory。如果你之前有传进来callFactory,那么就用你传进来的callFactory。如果你没有,就new一个OkHttpClient()对象。所以我们得知了,如果你需要设置OkHttpClient,你只需要传进去一个你设置好的的OkHttpClient即可。就像这样Retrofit.Builder().callFactory(...)
下面的callbackExecutor用处是把回调传递到UI线程!这个你得关注下。
adapterFactories主要用来存储对Call进行转化的对象。
converterFactories主要用来存储转化数据对象,这里的addConverterFactory(GsonConverterFactory.create())就是添加了转化成Gson的支持。
2.Call的创建过程
retrofit.create(LoginAPI.class)
看看create方法
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (validateEagerly) { eagerlyValidateMethods(service); } 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); } }); }别看这么长,都是长在了return里啊!他这里采用的是动态代理。具体讲静态和动态代理就不讲了,就简单讲下。(代理是为了扩充功能的,比如你原来的方法功能不够, 你又不能修改这个方法,那么用代理就重新写个方法,给他前后加上逻辑。简单来说就是这样。讲多一点,就是能修改也不要修改,你要保证功能的原子性)所以呢,我们执行LoginApi里的login方法,其实等同于执行了这个invoke方法了(这个invoke方法就是扩展功能后的方法了)。我们讲了一串废话,其实只需要重点关注下loadServiceMethod方法即可。
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
ServiceMethod loadServiceMethod(Method method) { ServiceMethod result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder(this, method).build(); serviceMethodCache.put(method, result); } } return result; }先通过result = serviceMethodCache.get(method);看看这个方法有没有缓存,之前有没有调用过(实际上,map是一个源码中经常用到的缓存器)。如果没有缓存,就创建一个并缓存下来。
看一下这个创建的方法
public ServiceMethod build() { 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); }
第一行的callAdapter最终会得到我们再Retrofit的build过程中adapterFactroies中添加进去的platform.defaultCallAdapterFactory(callbackExecutor)方法的get方法。defaultCallAdapterFactory指的是ExecutorCallAdapterFactory。
看一下ExecutorCallAdapterFactory的get方法
@Override public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } final Type responseType = Utils.getCallResponseType(returnType); return new CallAdapter<Call<?>>() { @Override public Type responseType() { return responseType; } @Override public <R> Call<R> adapt(Call<R> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; }会返回一个CallAdapter对象,这里的responseType方法会返回数据的真实类型。比如我们的LoginApi传入的是JSONObject,那么responseType返回的就是JSONObject类。而下面的adapt方法会创建ExecutorCallbackCall,它会把call的回调转发到UI线程,这样你就可以在回调完成后在UI线程里更新UI了,这个我们之前也提到过。
继续看ServiceMethod的build方法。responseConverter = createResponseConverter();这段代码把GsonConverterFactory(Converter.Factory的子类)添加到converterFactories列表中,表示返回的数据是支持转化成JSON对象的。
然后
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
parseMethodAnnotation(annotation);
}
实际上就是遍历一下方法的注解,解析一下方法的注解,看看我们到底是用的啥注解,啥请求(比如GET、POST)。
那么最后一个代码块不用说也是判断如QUERY、PART这种注解了。
最后回头看看Retrofit的create方法。
ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall);new了一个OkHttpCall的对象,把他传入adapt中。前面提到,adapt会创建ExecutorCallbackCall,并传入OkHttpCall。所以看一下ExecutorCallbackCall的代码。
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; } @Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("callback == null"); delegate.enqueue(new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { @Override public void run() { if (delegate.isCanceled()) { // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation. callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled")); } else { callback.onResponse(ExecutorCallbackCall.this, response); } } }); } @Override public void onFailure(Call<T> call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run() { callback.onFailure(ExecutorCallbackCall.this, t); } }); } }); }成功,失败回调都在这里了。所以我们可以得知,ExecutorCallbackCall是对于Call的封装。它通过callbackExecutor把请求回调到UI线程。当我们得到Call对象后会调用它的enqueue方法,其实调用的是ExecutorCallbackCall的enqueue。而delegate.enqueue显示最终调用的是delegate(传入的OkHttpCall)的enqueue方法。
3.Call的enqueue方法
所以根据上面所说,直接看OkHttpCall的enqueue方法即可
这里调用了okhttp3.Call的call的enqueue方法
call.enqueue(new okhttp3.Callback() {parseResponse这里调用了parseResponse方法
看看这个方法
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) { return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); 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; }根据返回的不同状态码code值做不同的操作。正常情况会调用到T body = serviceMethod.toResponse(catchingBody);看一下toResponse
/** Builds a method return value from an HTTP response body. */ T toResponse(ResponseBody body) throws IOException { return responseConverter.convert(body); }这个responseConverter就是之前ServiceMethod的build方法调用的createResponseConverter方法返回的Converter。我们传入的是GsonConverterFactory。说了这个东西这么多,还是直接看看GsonConverterFactory的源码吧。
@Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new GsonResponseBodyConverter<>(gson, adapter); }
它的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 { return adapter.read(jsonReader); } finally { value.close(); } } }这里会把回调的数据转换成JSON格式。
Call的enqueue方法主要做的是用OkHttp来请求网络,把返回的Response进行数据转换并回调给UI线程。所以就是对于OkHttp的封装。
讲的有点乱,最后贴3个图帮助理解。