前言
本文是Retrofit2進(jìn)階系列的第一篇---從源碼角度看Retrofit2實(shí)現(xiàn)原理,我會盡可能用簡潔的代碼幫大家理解Retrofit實(shí)現(xiàn)一次網(wǎng)絡(luò)請求的核心流程是怎樣的,這個流程整體上就4個步驟,是不復(fù)雜的,希望大家?guī)е判淖x下去,在文章末尾,我也為大家做出了簡單的總結(jié),希望能幫大家更好的理解這個框架,希望在讀文章的你能有一些收獲,能有更大的進(jìn)步。備注:基于
Retrofit2.4.0分析
系列文章:
Retrofit2進(jìn)階】---啟示、思想
先來看一個最基礎(chǔ)的網(wǎng)絡(luò)請求案例:
//1、創(chuàng)建Retrofit接口
public interface ApiService {
@GET("/")
Observable<String> getData();
@GET("/")
Call<String> getData2();
}
//2、retrofit相關(guān)配置
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://xxxx/")
.client(client)
//json轉(zhuǎn)換
.addConverterFactory(GsonConverterFactory.create())
//RxJava2轉(zhuǎn)換器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//創(chuàng)建接口對象
ApiService apiService = retrofit.create(ApiService.class);
//3、接口方法調(diào)用
3.1 call調(diào)用
apiService.getData2().enqueue();
3.2結(jié)合rxjava調(diào)用
apiService.getData().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
下面就來分析一下Retrofit2是如何完成一次完整的網(wǎng)絡(luò)請求的。
先來看一下Call調(diào)用
public interface ApiService {
@GET("/")
Call<String> getData2();
}
通過接口調(diào)用會返回一個Call對象,如果你看過OkHttp源碼的話,應(yīng)該會對這個Call很熟悉,它封裝了一個網(wǎng)絡(luò)請求的任務(wù),但是它卻不做網(wǎng)絡(luò)請求,而是通過調(diào)用enqueue()或者execute()來發(fā)起真正的網(wǎng)絡(luò)請求。
那這個Call對象如何生成的?其實(shí)可以在retrofit.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);
}
});
}
create()內(nèi)部的核心就一件事情,通過動態(tài)代理生成一個代理類對象,具體來說就是通過Proxy.newProxyInstance()來創(chuàng)建的。然后在回調(diào)方法invoke()內(nèi)部通過一系列解析,包裝,最終返回用于發(fā)起網(wǎng)絡(luò)請求的Call對象或者用于結(jié)合rxjava使用的Observable對象。
這里的關(guān)鍵點(diǎn)與難點(diǎn)在于,你要懂代理模式和動態(tài)代理,如果你還不會的話,建議先簡單學(xué)習(xí)一下再接著往下看,不然很多邏輯的連貫性你是不懂的。這里推薦一下我之前的一篇文章Java動態(tài)代理那些你容易忽略的細(xì)節(jié)。
先說一下Retrofit2動態(tài)代理的邏輯
//retrofit的API接口對象
ApiService apiService;
//創(chuàng)建代理對象
apiService = retrofit.create(ApiService.class);
//調(diào)用代理類中的方法
apiService.xxx();
首先生成一個代理類對象,當(dāng)調(diào)用代理類的方法時,會回調(diào)執(zhí)行InvocationHandler的invoke()方法
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//省略,不會執(zhí)行的代碼
//生成Call關(guān)鍵在這里
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
-
ServiceMethod是對接口中的方法進(jìn)行解析,包括注解、參數(shù),生成Http Request,具體來說是toRequest(),將response轉(zhuǎn)換為String或者實(shí)體類,具體說是toResponse(); -
OkHttpCall是對okhttp3.call的封裝,以及okhttp3的其他方法的調(diào)用; -
serviceMethod.callAdapter.adapt(okHttpCall);通過calladapter轉(zhuǎn)換器,將 okhttp3.call轉(zhuǎn)換成可以用于發(fā)起網(wǎng)絡(luò)請求的retrofit2.Call或者說用于rxjava的Observable
下面對ServiceMethod、 OkHttpCall 、CallAdapter做一個簡單的解釋,注意不是詳解,這樣可以讓你避免陷入一葉障目的困境。我們先搞清楚主流程,那些細(xì)枝末節(jié)后面再看唄。
1、ServiceMethod
它是通過建造者模式來創(chuàng)建的,核心內(nèi)容如下:
這部分內(nèi)容先不用詳細(xì)理解,可以先看個大概,后面再單獨(dú)來看
public ServiceMethod build() {
//獲取具體的網(wǎng)絡(luò)適配器對象CallAdapter,如果retrofit配置了rxjava2轉(zhuǎn)換器,那這里就是RxJava2CallAdapter
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
//獲取響應(yīng)轉(zhuǎn)換器
responseConverter = createResponseConverter();
//解析方法注解,比如@GET、@POST、@FormUrlEncoded等等
//這里解析完畢之后可以獲取到Http請求方式,請求體,url等信息
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//解析當(dāng)前方法的參數(shù)
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);
}
}
2、OkHttpCall
它繼承于Retrofit2.Call,內(nèi)部就是對okhttp3一系列操作的封裝,甚至說代碼都是直接copy的。這里就不展開詳細(xì)解釋了。注意:不要被OkHttpCall的名字所迷惑,它不是okhttp3中的call,而是Retrofit2.Call
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;
private final @Nullable Object[] args;
private volatile boolean canceled;
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
@GuardedBy("this")
private @Nullable Throwable creationFailure; // Either a RuntimeException or IOException.
@GuardedBy("this")
private boolean executed;
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
3、callAdapter
上面invoke()方法中,最后一步是return serviceMethod.callAdapter.adapt(okHttpCall);,
上面有提到過,這一步的作用是返回一個Retrofit2.Call或者Observable。
這里的CallAdapter對象是一個接口對象,所以需要找到他的實(shí)現(xiàn)類。先回顧一下在Retrofit配置的時候,有這么一行代碼.addCallAdapterFactory(RxJava2CallAdapterFactory.create()),它可以將接口方法返回Observable,如果不加這個配置,會如何呢?答案是會返回Retrofit2.Call類型,具體是如何產(chǎn)生的,請看如下流程:
retrofit.build()---->platform.defaultCallAdapterFactory()--->Platform.ExecutorCallAdapterFactory--->ExecutorCallAdapterFactory.ExecutorCallbackCall
3.1 Retrofit沒有配置callAdapter時
serviceMethod.callAdapter就是ExecutorCallAdapterFactory.get()返回的CallAdapter實(shí)例,然后調(diào)用它的adapt會返回一個ExecutorCallbackCall對象。簡單看一下這個對象,它是繼承于Call的。
static final class ExecutorCallbackCall<T> implements Call<T> {
3.2 Retrofit配置了RxJava2CallAdapterFactory時
serviceMethod.callAdapter就是RxJava2CallAdapter,調(diào)用它的adapt會返回一個Observable對象。
到這里就搞清楚了生成Retrofit2.Call或者Observable的整個流程,最后就只剩下一步了,發(fā)起網(wǎng)絡(luò)請求和響應(yīng)是如何實(shí)現(xiàn)的。
4、網(wǎng)絡(luò)請求的實(shí)現(xiàn)
4.1 Call實(shí)現(xiàn)網(wǎng)絡(luò)請求
上面提到過Call對象是通過enqueue()或者execute()發(fā)起網(wǎng)絡(luò)請求的,而這個Call對象實(shí)際上是ExecutorCallbackCall的實(shí)例
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "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);
}
});
}
});
}
所以,當(dāng)我們外部調(diào)用enqueue()時,實(shí)際調(diào)用的就是ExecutorCallbackCall.enqueue(),而這里的delegate是OkHttpCall,所以最終會由OkHttpCall內(nèi)部的okhttp3去執(zhí)行。
這里還有一個關(guān)鍵點(diǎn)callbackExecutor,它的來源如下:
//Platform.MainThreadExecutor.java
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
可以看到enqueue的回調(diào)結(jié)果是在主線程中。
4.2 Observable實(shí)現(xiàn)網(wǎng)絡(luò)請求
從之前的分析中,我們可以知道Observable是在RxJava2CallAdapter內(nèi)部的adapt()方法返回的:
@Override public Object adapt(Call<R> call) {
//創(chuàng)建一個發(fā)射網(wǎng)絡(luò)返回數(shù)據(jù)的Observable
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;
}
//這里為null
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
//可以轉(zhuǎn)換成Flowable
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
關(guān)鍵點(diǎn)在第一行代碼,isAsync返回true,所以看一下CallEnqueueObservable的實(shí)現(xiàn)
final class CallEnqueueObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallEnqueueObservable(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();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
如果你看過RxJava2的源碼的話,應(yīng)該對這段代碼非常熟悉,每個Observable都會去調(diào)用subscribeActual()方法。這里通過call.enqueue()去發(fā)起網(wǎng)絡(luò)請求,然后通過CallCallback回調(diào)
private static final class CallCallback<T> implements Disposable, Callback<T> {
private final Call<?> call;
private final Observer<? super Response<T>> observer;
boolean terminated = false;
CallCallback(Call<?> call, Observer<? super Response<T>> observer) {
this.call = call;
this.observer = observer;
}
@Override public void onResponse(Call<T> call, Response<T> response) {
if (call.isCanceled()) return;
try {
observer.onNext(response);
if (!call.isCanceled()) {
terminated = true;
observer.onComplete();
}
} catch (Throwable t) {
if (terminated) {
RxJavaPlugins.onError(t);
} else if (!call.isCanceled()) {
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
}
@Override public void onFailure(Call<T> call, Throwable t) {
if (call.isCanceled()) return;
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
@Override public void dispose() {
call.cancel();
}
@Override public boolean isDisposed() {
return call.isCanceled();
}
}
}
這里的邏輯也很簡單,就是把網(wǎng)絡(luò)請求的結(jié)果發(fā)射出去。
到這里,Retrofit2網(wǎng)絡(luò)執(zhí)行流程的源碼分析就算完了。其實(shí)這里的類不算多,邏輯上也比較清晰,但是需要掌握的知識點(diǎn)比較雜,比如入口處的動態(tài)代理,中間的OkHttp、RxJava2源碼。所以,這里建議基礎(chǔ)薄弱的同學(xué),看完這些內(nèi)容之后再回頭來看Retrofit2,理解會更加深刻。
總結(jié)
流程
1、通過建造者模式創(chuàng)建一個Retrofit實(shí)例,也就是做Retrofit相關(guān)配置;
2、通過Retrofit對象的creat()方法創(chuàng)建一個代理對象,當(dāng)調(diào)用接口方法時,都會調(diào)用動態(tài)代理的invoke()方法;
3、invoke()內(nèi)部做了3件事情:
- 3.1 會對method進(jìn)行解析,最后生成
ServiceMethod對象,并緩存起來,下次調(diào)用就不需要解析了; - 3.2 將原始的
okhttp3.call封裝成OkHttpCall - 3.3 通過
CallAdapter轉(zhuǎn)換成Call對象或者Observable對象
4、如果返回Call對象,調(diào)用execute或者enqueue方法去做網(wǎng)絡(luò)請求;如果返回Observable對象,則結(jié)合rxjava2做后續(xù)的操作。
結(jié)論:
Retrofit是一個封裝了網(wǎng)絡(luò)請求的框架,它本身是不做網(wǎng)絡(luò)請求的,而是通過
Okhttp實(shí)現(xiàn)的;Retrofit提供了一種更簡潔的發(fā)起網(wǎng)絡(luò)請求的方式,具體來說是通過接口和注解的方式來簡化網(wǎng)絡(luò)請求相關(guān)的一系列配置;
可擴(kuò)展性。比如說Client、數(shù)據(jù)轉(zhuǎn)換Gson、RxJava適配等。