此文章只对 Retrofit构建流程 和 网络请求流程 的主干思路分析。
1.Retrofit创建
Retrofit源码我们需要从Retrofit的使用开始,Retrofit明显使用了Builder模式进行初始化创建,根据Retrofit对象创建主要有六个步骤分析,分别为Builder()、baseUrl(String baseUrl)、client()、addConverterFactory()、addCallAdapterFactory()、build()。
Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl(HOST)
.client(new OkHttpClient())
.addConverterFactory(FastJsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
1.1 Builder()构建
Builder(Platform platform) {
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
}
public Builder() {
// 获取平台(有Android、Java8)
this(Platform.get());
}
Builder(Retrofit retrofit) {
platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;
converterFactories.addAll(retrofit.converterFactories);
adapterFactories.addAll(retrofit.adapterFactories);
// Remove the default, platform-aware call adapter added by build().
adapterFactories.remove(adapterFactories.size() - 1);
callbackExecutor = retrofit.callbackExecutor;
validateEagerly = retrofit.validateEagerly;
}
构造方法中参数Platform.get() 我们来看一下获取的是什么
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) {
}
return new Platform();
}
可以看到Retrofit支持多平台包括Android和Java8,它会根据不同的平台设置不同的线程池,此处记录下当前的平台标记,后面使用到再做分析。
1.2 baseUrl(String baseUrl)
/**
* Set the API base URL.
*
* @see #baseUrl(HttpUrl)
*/
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
很容易理解,baseUrl(String baseUrl)是配置服务器地址,如果为空会抛出异常。
1.3 client(OkHttpClient client)
/**
* The HTTP client used for requests.
* <p>
* This is a convenience method for calling {@link #callFactory}.
*/
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
/**
* Specify a custom call factory for creating {@link Call} instances.
* <p>
* Note: Calling {@link #client} automatically sets this value.
*/
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
client(OkHttpClient client)方法也只是记录下传进来的OkHttpClient对象,如果不传后面使用的时候会直接new OkHttpClient()进行赋值,所以需要对OkHttpClient对象进行超时设置或者其他拦截可以传入该对象。
1.4 addConverterFactory(FastJsonConverterFactory.create())
/** Add converter factory for serialization and deserialization of objects. */
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
细心的同学已经注意到我们在Buidler()构造的时候有以下一行代码,那我们主动将一个FastJsonConverterFactory添加到converterFactories中是什么用意呢?
converterFactories.add(new BuiltInConverters())
其实Converter主要作用是将HTTP返回的数据解析成Java对象,比如我们常见的网络传输数据Xml、Json、Protobuf等,而FastJsonConverterFactory则将Json转换成我们要的Java对象,不需要我们重新去解析Json数据。
1.5 addCallAdapterFactory(RxJava2CallAdapterFactory.create())
/**
* Add a call adapter factory for supporting service method return types other than {@link
* Call}.
*/
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
可以看到CallAdapter同样是被使用list集合维护的对象,说明是可以添加多个的,但也会有默认的一个,我看下面build()方法的源码。
1.6 build()
/**
* Create the {@link Retrofit} instance using the configured values.
* <p>
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
* OkHttpClient} will be created and used.
*/
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);
}
build()方法的思路分析一下,baseUrl为空则抛出异常;callFactory为传入的OkHttpClient对象,如果没传就new一个直接使用;callbackExecutor为线程池执行类,根据平台platform创建线程池使用,platform.defaultCallAdapterFactory(callbackExecutor)意思就是默认添加了一个CallAdapter,如果有平台线程池创建ExecutorCallAdapterFactory。callAdapter其实也是运用了适配器模式,是网络请求器Call的适配器,而Retrofit中Call就是指OkHttp,那么CallAdapter就是用来将OkHttp适配给不同平台的,Retrofit主要提供了以下四种CallAdapter:
-
ExecutorCallAdapterFactory(默认)
-
GuavaCallAdapterFactory
-
Java8CallAdapterFactory
-
RxJavaCallAdapterFactory
1.7 Builder模式流程图
综上使用Builder模式创建的Retrofit实例大致思路分析完毕,Retrofit负责接收我们配置的功能然后进行对象的初始化,这个就是Builder模式屏蔽掉创建对象的复杂过程的好处,下面梳理下流程图:
2.网络请求分析
ApiService api = retrofit.create(ApiService.java);
ApiResponse response = api.request(String param);
上面为最简单的网络请求创建,具体RxJava这里不做详细说明,主要分析一下create()方法里面做的处理,下面我们先来看看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, @Nullable 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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
我们主要看一下Proxy.newProxyInstance()这个方法,该方法三个参数,第一个是service类的类加载器,第二个service类,第三个回调接口InvocationHandler。其实就是通过动态代理生成网络请求的代理类,代理类生成后调用请求时就会被代理类拦截下来直接进入InvocationHandler的invoke方法。下面我们了解该方法:
2.1 invoke回调
该回调方法有三个参数,第一个代理类对象,第二个为被调用的方法(上面api.request(String param)中的request),第三个为参数(上面api.request(String param)中的param)。主要做了三步操作,第一步:收到被调用方法和传递的参数后,调用loadServiceMethod方法来生成一个ServiceMethod对象,这里一个ServiceMethod对象对应我们Service中的一个方法,相当于做了一层封装;第二步:创建OkHttpCall对象;第三步:CallAdapter使用。接下来重点看一下loadServiceMethod方法。
2.1.1 loadServiceMethod
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
它调用了ServiceMethod类,ServiceMethod类也是使用了Builder构建模式,我们看一下ServiceMethod的Builder方法。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
// 接口中的方法名
this.method = method;
// 接口中的方法注解
this.methodAnnotations = method.getAnnotations();
// 接口中方法里的参数类型
this.parameterTypes = method.getGenericParameterTypes();
// 接口中方法里的注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
再看看build方法
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);
}
分析下主要思路:
-
对注解的合法性进行检验,例如HTTP请求方法是GET还是POST,都不是则抛出异常。
-
根据方法的返回值类型和方法注解,分别从Retorfit对象的CallAdapter列表和Converter列表中分别获取对应的CallAdapter和Converter。
-
将传递过来的参数封装到ParameterHandler中,供后面网络请求使用。
2.1.2 使用OkHttpCall进行网络请求
loadServiceMethod方法之后,在invoke回调里使用new OkHttpCall<>(serviceMethod, args)创建了网络请求类OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
private final ServiceMethod<T, ?> serviceMethod;
private final @Nullable Object[] args;
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
创建OkHttpCall时把刚才创建的ServiceMethod对象传了进去,就简单的存了一下,暂时并没做任何操作,我们继续往下看。
2.1.3 CallAdapter的使用
invoke最后一行
return serviceMethod.callAdapter.adapt(okHttpCall);
最后是调用了callAdapter的adapt方法,上面讲到Retrofit使用什么CallAdapter是根据我们在接口中定义的方法返回值,在例子中我们使用的是RxJava2CallAdapter,我们直接看该类的adapt方法吧
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return RxJavaPlugins.onAssembly(observable);
}
首先在adapt方法中会先判断我们使用的是同步请求还是异步请求,这里我们分析同步请求里面做了什么操作(区别就是简单的异步还是同步请求而已)
final class CallExecuteObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallExecuteObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallDisposable disposable = new CallDisposable(call);
observer.onSubscribe(disposable);
if (disposable.isDisposed()) {
return;
}
boolean terminated = false;
try {
Response<T> response = call.execute();
if (!disposable.isDisposed()) {
observer.onNext(response);
}
if (!disposable.isDisposed()) {
terminated = true;
observer.onComplete();
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (terminated) {
RxJavaPlugins.onError(t);
} else if (!disposable.isDisposed()) {
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
}
private static final class CallDisposable implements Disposable {
private final Call<?> call;
private volatile boolean disposed;
CallDisposable(Call<?> call) {
this.call = call;
}
@Override public void dispose() {
disposed = true;
call.cancel();
}
@Override public boolean isDisposed() {
return disposed;
}
}
}
subscribeActual方法中调用了OkHttpCall的execute方法进行网络请求,请求响应回来后,通过RxJava的操作符对返回的数据进行转换,并切换线程。至此,Retrofit进行一次网络请求的主干思路就分析完了,是不是觉得很简单呢。下面我们看一下流程图