注:本文基于 Retrofit2.0版本,并配合 RxJava 來分析。
com.squareup.retrofit2:retrofit:2.0.0
com.squareup.retrofit2:converter-gson:2.0.0
com.squareup.retrofit2:adapter-rxjava:2.0.0
?
? Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to how requests are made.
本文主要通過分析 Retrofit 與 RxJava 的合作流程 來深入理解 Retrofit的工作原理,并且解答自己心中的疑惑。
疑惑
- 我們調(diào)用接口的方法后是怎么發(fā)送請(qǐng)求的?這背后發(fā)生了什么?
- Retrofit 與 OkHttp 是怎么合作的?
- Retrofit 中的數(shù)據(jù)究竟是怎么處理的?它是怎么返回 RxJava.Observable 的?
Retrofit 的基本使用
public interface ApiService{
@GET("data/Android/"+ GankConfig.PAGE_COUNT+"/{page}")
Observable<GankResponse> getAndroid(@Path("page") int page);
}
// Builder 模式來構(gòu)建 retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build();
// 通過 retrofit.create 方法來生成 service(非四大組件中的 Service)
ApiService service = retrofit.create(ApiService.class);
// 發(fā)起請(qǐng)求 獲取數(shù)據(jù)
Observable<GankResponse> observable= service.getAndroid(1);
observable....
Retrofit 就這樣經(jīng)過簡(jiǎn)單的配置后就可以向服務(wù)器請(qǐng)求數(shù)據(jù)了,超級(jí)簡(jiǎn)單。
Retrofit.create 方法分析
Retrofit的create
方法作為 Retrofit 的入口,當(dāng)然得第一個(gè)分析。
public <T> T create(final Class<T> service) {
//驗(yàn)證接口是否合理
Utils.validateServiceInterface(service);
//默認(rèn) false
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 動(dòng)態(tài)代理
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
// 平臺(tái)的抽象,指定默認(rèn)的 CallbackExecutor CallAdapterFactory用, 這里 Android 平臺(tái)是 Android (Java8 iOS 咱不管)
private final Platform platform = Platform.get();
//ApiService 中的方法調(diào)用都會(huì)走到這里
@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.
// 注釋已經(jīng)說明 Object 的方法不管
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// java8 的默認(rèn)方法,Android暫不支持默認(rèn)方法,所以暫時(shí)也不需要管
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 重點(diǎn)了 后面分析
// 為 Method 生成一個(gè) ServiceMethod
ServiceMethod serviceMethod = loadServiceMethod(method);
// 再包裝成 OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); // 請(qǐng)求
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
在上面的代碼中可以看到,Retrofit 的主要原理是利用了 Java 的動(dòng)態(tài)代理技術(shù),把 ApiService 的方法調(diào)用集中到了InvocationHandler.invoke
,再構(gòu)建了ServiceMethod ,OKHttpCall,返回 callAdapter.adapt
的結(jié)果。
要弄清楚,還需要分析那最后三行代碼。
一步一步來。
ServiceMethod的職責(zé)以及 loadServiceMethod分析
我認(rèn)為 ServiceMethod 是接口具體方法的抽象,它主要負(fù)責(zé)解析它對(duì)應(yīng)的 method
的各種參數(shù)(它有各種如 parseHeaders
的方法),比如注解(@Get),入?yún)?,另外還負(fù)責(zé)獲取 callAdapter,responseConverter等Retrofit配置,好為后面的okhttp3.Request
做好參數(shù)準(zhǔn)備,它的toRequest
為 OkHttp 提供 Request,可以說它承載了后續(xù) Http 請(qǐng)求所需的一切參數(shù)。
再分析loadServiceMethod
,比較簡(jiǎn)單。
// serviceMethodCache 的定義
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
// 獲取method對(duì)應(yīng)的 ServiceMethod
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;
}
loadServiceMethod
方法,負(fù)責(zé) 為 method
生成一個(gè) ServiceMethod ,并且給 ServiceMethod 做了緩存。
動(dòng)態(tài)代理是有一定的性能損耗的,并且ServiceMethod 的創(chuàng)建伴隨著各種注解參數(shù)解析,這也是耗時(shí)間的,在加上一個(gè) App 調(diào)用接口是非常頻繁的,如果每次接口請(qǐng)求都需要重新生成那么有浪費(fèi)資源損害性能的可能,所以這里做了一份緩存來提高效率。
OkHttpCall
再接下去往后看OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
,是再為 ServiceMethod 以及 args(參數(shù))生成了一個(gè) OkHttpCall
。
從 OkHttpCall
這個(gè)名字來看就能猜到,它是對(duì) OkHttp3.Call
的組合包裝,事實(shí)上,它也確實(shí)是。(OkHttpCall
中有一個(gè)成員okhttp3.Call rawCall
)。
callAdapter.adapt流程分析
最后return serviceMethod.callAdapter.adapt(okHttpCall)
似乎是走到了最后一步。
如果說前面的都是準(zhǔn)備的話,那么到這里就是真的要行動(dòng)了。
來分析一下,這里涉及到的 callAdapter
,是由我們配置 Retrofit 的 addCallAdapterFactory
方法中傳入的RxJavaCallAdapterFactory.create()
生成,實(shí)例為RxJavaCallAdapterFactory
。
實(shí)例的生成大致流程為:
ServiceMethod.Bulider.Build()
->ServiceMethod.createCallAdapter()
->retrofit.callAdapter()
->adapterFactories遍歷
? ->最終到RxJavaCallAdapterFactory.get()#getCallAdapter()
? ->return return new SimpleCallAdapter(observableType, scheduler);
由于使用了 RxJava ,我們最終得到的 callAdapter
為 SimpleCallAdapter
,所以接下去分析SimpleCallAdapter
的 adapt
方法:
這里涉及到的 CallOnSubscriber
后面有給出:
@Override public <R> Observable<R> adapt(Call<R> call) {
// 這里的 call 是 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args) 生成的 okHttpCall
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //
.flatMap(new Func1<Response<R>, Observable<R>>() {
@Override public Observable<R> call(Response<R> response) {
if (response.isSuccessful()) {
return Observable.just(response.body());
}
return Observable.error(new HttpException(response));
}
});
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
}
static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
private final Call<T> originalCall;
CallOnSubscribe(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override public void call(final Subscriber<? super Response<T>> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
final Call<T> call = originalCall.clone();
// Attempt to cancel the call if it is still in-flight on unsubscription.
// 當(dāng)我們?nèi)∠嗛喌臅r(shí)候 會(huì)取消請(qǐng)求 棒棒噠
subscriber.add(Subscriptions.create(new Action0() {
@Override public void call() {
call.cancel();
}
}));
try {
// call 是 OkHttpCall 的實(shí)例
Response<T> response = call.execute();
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(response);
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (!subscriber.isUnsubscribed()) {
subscriber.onError(t);
}
return;
}
if (!subscriber.isUnsubscribed()) {
subscriber.onCompleted();
}
}
}
SimpleCallAdapter.adapt 很簡(jiǎn)單,創(chuàng)建一個(gè) Observable獲取CallOnSubscribe中的Response<T> 通過 flatMap轉(zhuǎn)成Observable<R>后返回。這里去發(fā)送請(qǐng)求獲取數(shù)據(jù)的任務(wù)在CallOnSubscribe.call 方法之中。并且最后走到了 okHttpCall.execute 中去了。
// OkHttpCall.execute
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
//同一個(gè)請(qǐng)求 不能執(zhí)行兩次
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
// ...省略 Execption 處理
call = rawCall;
if (call == null) {
try {
// 創(chuàng)建 okhttp3.call
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
// 請(qǐng)求并解析response 這個(gè) call 是 okhttp3.call 是真交給 OkHttp 去發(fā)送請(qǐng)求了
return parseResponse(call.execute());
}
// 解析 response
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
//... 省略一些處理 只顯示關(guān)鍵代碼
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
// serviceMethod.toResponse
T toResponse(ResponseBody body) throws IOException {
// 還記得嗎?這就是我們配置Retrofit時(shí)候的 converter
return responseConverter.convert(body);
}
經(jīng)過一連串的處理,最終在 OkHttpCall.execute() 的方法中生成 okhttp3.call 交給 OkHttpClient 去發(fā)送請(qǐng)求,再由我們配置的 Converter(本文為GsonConverterFactory) 處理 Response,返回給SimpleCallAdapter處理,返回我們最終所需要的Observable。
流程分析流程圖總結(jié)
總體的流程圖整理如下:
解答疑問
對(duì)于之前的疑問可以作答了。
第一個(gè)疑問: 我們調(diào)用接口的方法后是怎么發(fā)送請(qǐng)求的?這背后發(fā)生了什么?
Retrofit 使用了動(dòng)態(tài)代理給我們定義的接口設(shè)置了代理,當(dāng)我們調(diào)用接口的方法時(shí),Retrofit 會(huì)攔截下來,然后經(jīng)過一系列處理,比如解析方法的注解等,生成了 Call Request 等OKHttp所需的資源,最后交給 OkHttp 去發(fā)送請(qǐng)求, 此間經(jīng)過 callAdapter,convertr 的處理,最后拿到我們所需要的數(shù)據(jù)。
第二個(gè)疑問: Retrofit 與 OkHttp 是怎么合作的?
在Retrofit 中,ServiceMethod 承載了一個(gè) Http 請(qǐng)求的所有參數(shù),OkHttpCall 為 okhttp3.call 的組合包裝,由它們倆合作,生成用于 OkHttp所需的 Request以及okhttp3.Call,交給 OkHttp 去發(fā)送請(qǐng)求。(在本文環(huán)境下具體用的是 call.execute()
)
可以說 Retrofit 為 OkHttp 再封裝了一層,并增添了不少功能以及擴(kuò)展,減少了開發(fā)使用成本。
第三個(gè)疑問: Retrofit 中的數(shù)據(jù)究竟是怎么處理的?它是怎么返回 RxJava.Observable 的?
Retrofit 中的數(shù)據(jù)其實(shí)是交給了 callAdapter 以及 converter 去處理,callAdapter 負(fù)責(zé)把 okHttpCall 轉(zhuǎn)成我們所需的 Observable類型(本文環(huán)境),converter負(fù)責(zé)把服務(wù)器返回的數(shù)據(jù)轉(zhuǎn)成具體的實(shí)體類。
小結(jié)
Retrofit 的源碼其實(shí)非常好跟也非常好理解,不像看 framework 的代碼,跟著跟著就不見了。
另外 Retrofit的代碼確實(shí)非常漂亮,將設(shè)計(jì)模式運(yùn)用的可以說是爐火純青,非常值得學(xué)習(xí)。