Android技能樹 — 網路小結(7)之 Retrofit原始碼詳細解析

前言:
哈哈,其實寫的還是很水,各位原諒我O(∩_∩)O。
介於自己的網路方面知識爛的一塌糊塗,所以準備寫相關網路的文章,但是考慮全部寫在一篇太長了,所以分開寫,希望大家能仔細看,最好可以指出我的錯誤,讓我也能糾正。
1.講解相關的整個網路體系結構:
2.講解相關網路的重要知識點,比如很多人都聽過相關網路方面的名詞,但是僅限於聽過而已,什麼tcp ,udp ,socket ,websocket, http ,https ,然後webservice是啥,跟websocket很像,socket和websocket啥關係長的也很像,session,token,cookie又是啥。
Android技能樹 — 網路小結(3)之HTTP/HTTPS
Android技能樹 — 網路小結(4)之socket/websocket/webservice
相關網路知識點小結- cookie/session/token(待寫)
3.相關的第三方框架的原始碼解析,畢竟現在面試個大點的公司,okhttp和retrofit原始碼是必問的。
Android技能樹 — 網路小結(6)之 OkHttp超超超超超超超詳細解析
Android技能樹 — 網路小結(7)之 Retrofit原始碼詳細解析
正文
因為我平時使用的都是Rxjava2 + Retrofit ,所以我相關的原始碼解析都是配合RxJava來的,而不是Call返回物件。
讀本文的我推薦大家最好對OKHttp原始碼有所瞭解,再來看本文,因為Retrofit內部還是通過OkHttp發出網路請求。大家也可以看我前面寫的: Android技能樹 — 網路小結之 OkHttp超超超超超超超詳細解析 ,
<font color = "red">同時本文不會再去教大家Retrofit的基礎使用,如果要看一些簡單使用,可以看下面的一些推薦部落格:</font>
Android Retrofit 2.0 的詳細 使用攻略(含例項講解)
Android:Retrofit 結合 RxJava的優雅使用(含例項教程)
我們先上一張別的大佬部落格中的一張圖:

這個圖畫的很好,但是這個圖更多的是從大局觀來看,所以如果對於原始碼不是有一些基礎瞭解的話,看這個圖很容易就忘記。
看過我的Okhttp原始碼分析的文章: Android技能樹 — 網路小結之 OkHttp超超超超超超超詳細解析 ,我們文中的Okhttp流程圖就是跟著原始碼一步步來畫的。我更喜歡是跟著原始碼一步步來畫流程圖(PS:其實是我水平太差了,無法一下子總結處第三方庫的各種設計模式的使用),所以Retrofit我也畫了下面這個圖:

而等會我們分析完這個跟著原始碼分析的流程圖後,再回頭看上面的別人部落格中的總結的Retrofit結構圖,就會很簡單了。
首先我們來確定總體大綱:
我們知道我們的目標是要發起一次網路請求,他有這麼幾步:
- 告訴它一些基本資訊,比如url地址,網路請求方式(get、post、...等),請求引數值。然後拼裝成一個標準的網路Request請求的格式發出去。<font color = "red">所以這裡有二步動作:1.先解析我們寫的引數,2.再解析完後拼裝成標準的網路Request請求格式</font>
- 發出請求後,接收到了後臺的Response返回結果,我們要把Resonse轉換成我們想要的返回結果。但是我們寫的想要的返回結果又有二大關鍵地方,我們平常的返回結果可能是
X <Y>
,我們先來看外面的X的型別
,比如我們常見的返回結果是Call<Y> 和 Observable<Y>
,所以我們在轉換的時候一是要考慮最外面的那個返回型別的轉換。另外一個是Y的型別
,也就是裡面我們具體寫的Bean物件,比如我們直接返回字串,那可能就是Observable<String>
,又或者是自己定義的xxxBean物件,那就是Observable<xxxBean>
。<font color = "red">所以我們要有二類轉換:1.外層的結果型別,比如Call或者Observable等,2.是泛型裡面填的具體的Bean物件型別</font>
所以我們總結起來就需要四步:
<font color = "red">
- 解析並拿到我們寫的一些引數(url,請求方式(post/get),請求引數......)
- 根據我們寫的引數,拼成一個網路請求Request,去幫我們發起請求。
- Response如何轉換成Call或者Observable等返回型別,和第4步中的Bean物件拼成了Call《Bean》或者Observable《Bean》
- Response如何轉換成我們所需要的具體的Bean物件。
</font>
沒錯,下次別人問你,你就心裡有數了,到底Retrofit做了什麼內容,你就跟別人說很簡單啦,大致做了上面四步,逼格一下子提高了。。
1. 建立Retrofit物件

我這裡直接先把建立Retrofit的物件的程式碼寫上:
Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl("https://xxxx.com/") .build();
不要問建立Retrofit的各自的方法是幹嘛的,我們後面會一步步講解。
2. 如何解析並拿到我們寫的引數
我們知道我們平常是這樣寫的:
我們隨便寫一個常見的獲取某個使用者的個人資訊介面來說明:
InfoApi.java: interface InfoApi{ @GET("userinfo.do") Observable<UserBean> getInfo(@Query("name") String nameStr); }
那我們要拿到:
- path值:上面建立Retrofit時候傳入的baseUrl +
userinfo.do
="https://xxxx.com/userinfo.do"
- 網路請求的方式:
GET請求
- 傳送的引數query :
name=nameStr
最終我們發現是GET請求,所以這麼拼在一起: path + "?" + query = http://xxxx/userinfo.do?name=nameStr
所以我們來看如何一步步拿到相關引數:
我們知道上面寫的 InfoApi.java
是要被retrofit載入進去的:
retrofit.create(InfoApi.class);
所以我們要來看 create
方法的具體操作前,我們先來了解一下基礎知識,那就是代理模式,如果知道代理模式的,直接可以忽略此處,直接往下看。
2.1 create方法:
在看create程式碼之間,我們要先學會代理模式相關知識

本來也想一步步長篇大論的寫下,但是後來看到一篇不錯的文章,寫的挺仔細的: java動態代理實現與原理詳細分析 ,希望大家能仔細看完,在看下面的內容。

我們點進去檢視具體的程式碼:
public <T> T create(final Class<T> service) { Utils.validateServiceInterface(service); if (this.validateEagerly) { this.eagerlyValidateMethods(service); } //'使用了代理模式' return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() { private final Platform platform = Platform.get(); public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } else if (this.platform.isDefaultMethod(method)) { return this.platform.invokeDefaultMethod(method, service, proxy, args); } else { //'我們可以看到我們寫的接口裡面的的method傳入到了loadServiceMethod方法裡面,從而得到了我們定義在method上面的相關引數資訊。' ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method); //'我們傳入的方法的引數args和上面獲得的ServiceMethod,一起傳入OkHttpCall建構函式中,得到OkHttpCall物件' OkHttpCall<Object> okHttpCall = new OkHttpCall(serviceMethod, args); return serviceMethod.adapt(okHttpCall); } } }); }
我們可以看到我們呼叫的 getInfo
這個method方法傳入了:
ServiceMethod<Object, Object> serviceMethod = Retrofit.this.loadServiceMethod(method);
我們進去檢視:
ServiceMethod<?, ?> loadServiceMethod(Method method) { //'從快取中去讀' ServiceMethod<?, ?> result = (ServiceMethod)this.serviceMethodCache.get(method); if (result != null) { return result; } else { Map var3 = this.serviceMethodCache; synchronized(this.serviceMethodCache) { result = (ServiceMethod)this.serviceMethodCache.get(method); if (result == null) { //'如果快取中沒有,則新建' result = (new retrofit2.ServiceMethod.Builder(this, method)).build(); //'新建完後再放入快取中' this.serviceMethodCache.put(method, result); } return result; } } }
我們可以看到新建的方法:
(new retrofit2.ServiceMethod.Builder(this, method)).build();
我們來看ServiceMethod類下的Builder的建構函式:
Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; //'Java特有的方法,可以獲取Java方法上面的註解標識,比如:@POST,@GET' this.methodAnnotations = method.getAnnotations(); //'獲取方法引數裡面定義的引數型別,比如:String,boolean' this.parameterTypes = method.getGenericParameterTypes(); //'獲取方法裡面的註解標識,比如:@Query,@Path' this.parameterAnnotationsArray = method.getParameterAnnotations(); }
是不是一下子就知道了,原來是通過這樣的方式拿到了我們寫在方法上面的一些引數值,如果還不清楚Method的這幾個方法,可以看下面的相關連結:</br>
Java獲取類、方法、屬性上的註解 </br>
java.lang.reflect.Method.getGenericParameterTypes()方法示例. </br>
使用反射獲得引數列表裡的註解getParameterAnnotations.我們建立ServiceMethod因為是使用的Builder模式,所以最終要呼叫build()方法來建立例項:
public ServiceMethod build() { //'建立了CallAdapter物件,具體幹嘛用的,具體後面會講解' 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物件,具體後面會講解' responseConverter = createResponseConverter(); //'對於我們寫的介面請求方法的方法上面的註解進行相關判斷,' for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } //'因為進行方法上面註解的解析了,所以httpMethod的也就相應的被賦值了, 如果為空,就說明你寫的請求介面方法沒有寫@GET等,就會丟擲異常' if (httpMethod == null) { throw methodError(“HTTP method annotation is required (e.g., @GET, @POST, etc.).”); } //'因為上面解析了,所以比如我們發現是@GET請求,這時候hasBody會是false,如果你還用了Multipart註解,就會報錯了,他要求是要有request body的,@GET請求是不能使用Multipart的' if (!hasBody) { if (isMultipart) { throw methodError( “Multipart can only be specified on HTTP methods with request body (e.g., @POST).”); } //'同上,表單提交是一定要求有request body的' 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]; //'遍歷我們獲取的方法裡面的註解集合,比如@Query,@Path等' 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.”); } //'然後對我們寫的方法內部引數註解進行判斷,看寫的是否正確等 這裡的判斷很長,比如如果你用的是註解@Body,那麼先判斷你是否用了方法上面的@FormEncode註解或者@Multipart註解, 不然就報錯,然後因為我們填的引數是物件了,所以內部需要通過RequestBodyConverter來進行轉換,把我們傳的物件,變成了RequestBody物件。 具體很多很多判斷,各種註解的判斷我都不一一講了,大家只要進去看方法詳細程式碼就可以了。' 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); }
好,我們已經成功拿到了我們的方法中的紅色框出來的部分,綠色的部分我們還沒有獲取。

而代理模式的invoke方法裡面的引數 @Nullable Object[] args,就是我們具體傳入的引數,比如我這麼寫:
getInfo("青蛙要fly");
args裡面就有了我們傳入的 "青蛙要fly"
字串。這樣我們是不是就獲取了上面的其中一個綠色框nameStr的內容了。
我們拿到包含了這些紅色框引數的ServiceMethod物件後,加上我們傳入的綠色的框的 nameStr的具體的值
,我們已經可以進行網路Request請求的所必要的引數了 (另外一個綠色的框只是用來最後網路請求成功後拿到的Response進行轉換,所以這時候不知道都不影響Request請求)

我們可以看到我們獲得到的資訊,又用來生成了OkHttpCall物件,然後呼叫了 serviceMethod.adapt(okHttpCall);
方法。
那我們可以看到create接下去已經沒有其他程式碼了,所以 serviceMethod.adapt(okHttpCall);
肯定會幫我們用剛才拿到的已知引數,幫我們拼成Request,完成一次網路請求。
3.根據我們寫的引數,拼成Request請求

我們上面已經說到了進入了 serviceMethod.adapt(okHttpCall);
方法了,我們點進去檢視:
T adapt(Call<R> call) { return callAdapter.adapt(call); }
我們可以看到是呼叫了callAdapter類的adapt方法。那這個callAdapter物件又是什麼呢?
還記不記得我們第一大步:建立Retrofit物件時候的程式碼:
Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) //'這裡傳入了CallAdapterFactory,而Factory類是用來建立具體的CallAdapter物件的工廠類' .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl("https://xxxx.com/") .build();
所以本文中我們使用的CallAdapter是RxJava2CallAdapterFactory建立的,我們先來看ServiceMethod裡面建立CallAdapter的方法:
private CallAdapter<T, R> createCallAdapter() { //'我們上面的介面請求方法綠色框裡面的返回型別還沒有拿到的,終於在這裡拿到了' Type returnType = method.getGenericReturnType(); //'如果方法的返回結果包含了泛型表示式、泛型、泛型陣列,就丟擲異常' if (Utils.hasUnresolvableType(returnType)) { throw methodError( “Method return type must not include a type variable or wildcard: %s”, returnType); } //'如果方法的返回結果是void,則丟擲異常' if (returnType == void.class) { throw methodError(“Service methods cannot return void.”); } //'我們前面提過的,獲取方法上的註解,比如@GET等' Annotation[] annotations = method.getAnnotations(); try { //'拿著我們的介面請求方法的返回物件及方法上的註解資訊,' //'去通過Retrofit類的callAdapter類去生成一個CallAdapter物件' return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, “Unable to create call adapter for %s”, returnType); } }
而Retrofit類中的這個callAdapter方法,我們不看都知道,通過我們前面建立Retrofit物件時候傳入的addCallAdapterFactory的工廠類來建立具體的CallAdapter,當然我們具體還是要具體程式碼一步步來看過程。
我們在呼叫addCallAdapterFactory加入我們的 RxJava2CallAdapterFactory.create()
,所以先來看下addCallAdapterFactory方法做了什麼:
public Builder addCallAdapterFactory(CallAdapter.Factory factory) { callAdapterFactories.add(checkNotNull(factory, "factory == null")); return this; }
我們可以簡單的看到,就是把我們的Factory工廠類物件加入到 private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
這個List佇列中而已。
那這個佇列到底都加了哪些工廠類的,如果我在建立Retrofit物件時候不呼叫 addCallAdapterFactory
方法,難道這個佇列就是空的????那又怎麼去生成CallAdapter物件?
首先肯定要加入我們自己傳入的Factory,有可能一個,也可能傳入多個:
Retrofit retrofit = new Retrofit.Builder() ........ .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addCallAdapterFactory(xxxxxxCallAdapterFactory.create()) .addCallAdapterFactory(yyyyyyCallAdapterFactory.create()) ........ ........ .build();
但是為了防止我們建立Retrofit物件時候不呼叫addCallAdapterFactory傳入自己的Factory,所以本身這個佇列還會加入預設的Factory:
//'看名字就知道,加入平臺的預設的CallAdapterFactory(有java8 和 Android Platform,我們這裡肯定是Android)' callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

當然這個ExecutorCallAdapterFactory肯定是繼承了CallAdapter.Factory:

我們已經知道了我們的CallAdapterFactory佇列裡面包含了哪些工廠類了。接下來我們再來具體的Retrofit的callAdapter的方法:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { //'因為可能有多個CallAdapterFactory工廠類,所以要每個工廠類都去試一下,有一個成功就直接返回了' return nextCallAdapter(null, returnType, annotations); } public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { checkNotNull(returnType, "returnType == null"); checkNotNull(annotations, "annotations == null"); int start = callAdapterFactories.indexOf(skipPast) + 1; //'迴圈遍歷所有的CallAdapterFactory,然後哪個能成功生成CallAdapter,就直接返回' for (int i = start, count = callAdapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } //'如果所有的CallAdapterFctory都不能使用,就拼接字串,丟擲異常' StringBuilder builder = new StringBuilder("Could not locate call adapter for ") .append(returnType) .append(".\n"); if (skipPast != null) { builder.append("Skipped:"); for (int i = 0; i < start; i++) { builder.append("\n* ").append(callAdapterFactories.get(i).getClass().getName()); } builder.append('\n'); } builder.append("Tried:"); for (int i = start, count = callAdapterFactories.size(); i < count; i++) { builder.append("\n* ").append(callAdapterFactories.get(i).getClass().getName()); } throw new IllegalArgumentException(builder.toString()); }
有可能有人會問,為什麼CallAdapterFactory有可能生成CallAdapter不成功??還要一個個去遍歷?
因為我們同時傳入了我們需要返回的物件的型別傳入到了CallAdapterFactory中,你說如果你是預設的 ExecutorCallAdapterFactory
工廠類,你卻傳入了Rxjava的返回相關引數,比如我們例子中的 Observable<UserBean>
,它的程式碼裡面都不認識這種返回型別,怎麼幫你去生成物件,而且程式碼也是加了判斷,如果返回型別不是Call型別,直接就退出了。
@Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { //'如果不是Call.class,直接退出生成CallAdapter物件' if (getRawType(returnType) != Call.class) { return null; } ....... ....... }
所以我們來看下RxJava2CallAdapterFactory裡面怎麼生成相應的CallAdapter的:
@Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { Class<?> rawType = getRawType(returnType); //'如果我們的返回型別是Completable,就直接返回RxJava2CallAdapter物件,裡面的responseType是void' if (rawType == Completable.class) { // Completable is not parameterized (which is what the rest of this method deals with) so it // can only be created with a single configuration. return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false, false, true); } //'判斷是否是Flowable或者Single或者Maybe' boolean isFlowable = rawType == Flowable.class; boolean isSingle = rawType == Single.class; boolean isMaybe = rawType == Maybe.class; //'如果既不是上面三種又不是Observable型別,直接返回null' if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) { return null; } boolean isResult = false; boolean isBody = false; Type responseType; //'如果不是泛型類的,比如Observable<XXXX> ,則拋異常' if (!(returnType instanceof ParameterizedType)) { String name = isFlowable ? "Flowable" : isSingle ? "Single" : isMaybe ? "Maybe" : "Observable"; throw new IllegalStateException(name + " return type must be parameterized" + " as " + name + "<Foo> or " + name + "<? extends Foo>"); } //'獲取泛型中的具體引數,比如Observable<xxxBean>中的xxxBean的type' Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType); //'獲取xxxBean具體的Class物件' Class<?> rawObservableType = getRawType(observableType); //'判斷我們上面獲取的泛型內容(xxxBean)是不是Response' if (rawObservableType == Response.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException("Response must be parameterized" + " as Response<Foo> or Response<? extends Foo>"); } responseType = getParameterUpperBound(0, (ParameterizedType) observableType); //'判斷我們上面獲取的泛型內容(xxxBean)是不是Result' } else if (rawObservableType == Result.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException("Result must be parameterized" + " as Result<Foo> or Result<? extends Foo>"); } responseType = getParameterUpperBound(0, (ParameterizedType) observableType); isResult = true; } else { //'我們平常開發泛型裡面填的肯定是自己的Bean物件 //所以最後走的是這裡的程式碼' responseType = observableType; //'同時isBody設定為true' isBody = true; } //'生成具體的Rxjava2CallAdapter物件' return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false); }
既然我們CallAdapter物件也建立完了,我們回到最剛開始的地方,還記得我們前面分析的程式碼是到了 callAdapter.adapt(okHttpCall)
(如果忘記的同學,可以重新回頭看下) 。
所以我們現在已經建立的Rxjava2CallAdapter物件了,我們來看下它的adapt方法:

@Override public Object adapt(Call<R> call) { /** '很多人會說這個isAsync,是否非同步是哪裡設定的, 其實就是再我們傳入Factory物件時候建立的。 Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) 我們看見建立Factory物件,可以是createAsync()或者create()方法二種來建立,從而決定是同步還是非同步操作 .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) 或者是 .addCallAdapterFactory(RxJava2CallAdapterFactory.create() .build();' */ //'我們可以看到上面根據是否非同步,建立不同的Observable物件,我們用複雜點的來講解吧, 就當我們建立的時候使用的是RxJava2CallAdapterFactory.createAsync()方法,所以拿到的物件是CallEnqueueObservable' Observable<Response<R>> responseObservable = isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call); //'因為我們Observable<xxxBean>裡面包含的是自己Bean,所以建立的時候isBody = true;' Observable<?> observable; if (isResult) { observable = new ResultObservable<>(responseObservable); } else if (isBody) { //'所以我們的Observable為BodyObservable' 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(); } //'所以最終返回了BodyObservable<CallEnqueueObservable>' return observable; }
BodyObservable看名字就知道是一個自定義Observable:
final class BodyObservable<T> extends Observable<T> { private final Observable<Response<T>> upstream; BodyObservable(Observable<Response<T>> upstream) { this.upstream = upstream; } @Override protected void subscribeActual(Observer<? super T> observer) { //'當有Observer註冊我們的Observable的時候, 其實是我們前面的傳入的CallEnqueueObservable去註冊了 一個BodyObserver<我們自己寫的Observer>' upstream.subscribe(new BodyObserver<T>(observer)); } }
所以核心還是我們傳入的 CallEnqueueObservable
這個Observable,所以最後還是要看這個類的原始碼:
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物件,傳入了使用者寫的我們前面建立的OkHttpCall物件和使用者寫的observer物件' CallCallback<T> callback = new CallCallback<>(call, observer); observer.onSubscribe(callback); //'然後呼叫了call的enqueue方法, 因為是OkHttpCall物件,所以我們直接看OkHttpCall物件的enqueue方法即可' call.enqueue(callback); } private static final class CallCallback<T> implements Disposable, Callback<T> { ....... ....... ....... } }
OkHttpCall的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 { //'建立Okhttp3的Call物件(畢竟最後發起網路請求是Okhttp,也要使用它的Call物件)' call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } //'常規Okhttp的操作,call.enqueue方法發起非同步請求,估計大家都看得懂,我就不多介紹了,我們直接看拿到返回的資料處理' call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { //'我們這裡成功的拿到了Okhttp3.Response物件, 所以使用parseResponse方法將rawResponse物件轉換成Retrofit的Response物件' response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } @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(); } } }); }
到這裡,我們已經成功的傳送了網路請求,並且拿到了主句
4. 如何將Resonse轉換成最終我們想要的結果物件

我們上面可以看到我們是講OkHttp3.Response物件轉換成了Retrofit.Response物件,我們具體來看下:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { //'把Okhttp3.Response中的body部分取出來' ResponseBody rawBody = rawResponse.body(); rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); //'我們就當成功請求回來的,所以code是200' 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 { //'核心程式碼: 把body部分,通過toResponse方法,變成我們寫入的泛型(也就是Observable<xxxBean>這個xxxBean物件' 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; } }
所以最終我們發現又回到了serviceMethod裡面了,相關的方法呼叫都在這裡面:
R toResponse(ResponseBody body) throws IOException { //'可以看到我們通過responseConverter轉換器來對body部分進行了轉換' return responseConverter.convert(body); }
這個responseConverter又是怎麼來的呢?我們再回到建立Retrofit物件的地方:
Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //'看見了ConverterFactory沒有,就是這裡傳入了我們的轉換器物件' .addConverterFactory(GsonConverterFactory.create()) .baseUrl("https://xxxx.com/") .build();
我們來看下具體的程式碼:
public final class GsonConverterFactory extends Converter.Factory { //'可以看到預設內部使用的是GSON來進行轉換' public static GsonConverterFactory create() { return create(new Gson()); } public static GsonConverterFactory create(Gson gson) { return new GsonConverterFactory(gson); } private final Gson gson; private GsonConverterFactory(Gson gson) { if (gson == null) throw new NullPointerException("gson == null"); this.gson = gson; } //'這個方法從名字就可以看出來,是用用來給ResponseBody轉換成我們要的物件' @Override public Converter<ResponseBody, ?> responseBodyConverter(final Type type, Annotation[] annotations, Retrofit retrofit) { Type newType = new ParameterizedType() { @Override public Type[] getActualTypeArguments() { return new Type[] { type }; } @Override public Type getOwnerType() { return null; } @Override public Type getRawType() { return HttpResult.class; } }; TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(newType)); //'可以看到,用在Response的轉換器是叫GsonResponseBodyConverter物件' return new GsonResponseBodyConverter<>(adapter); } //'這個名字也可以看出來是把我們傳入的物件轉換成RequestBody,從而發起請求' @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); //'可以看到,用在Request的轉換器是叫GsonRequestBodyConverter物件' return new GsonRequestBodyConverter<>(gson, adapter); } }
我們具體來看看 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 { //'根據傳入的ResponseBody得到JsonReader' JsonReader jsonReader = gson.newJsonReader(value.charStream()); try { //'很簡單,就是GSON進行相關的JSON解析' T result = adapter.read(jsonReader); if (jsonReader.peek() != JsonToken.END_DOCUMENT) { throw new JsonIOException("JSON document was not fully consumed."); } return result; } finally { value.close(); } } }
這裡我們看到了既然解析部分是在這裡,是不是我們可以做很多定製化操作,答案當然是Yes,比如我寫了個自定義的GsonResponseBodyConverter來進行替換(下面的類就隨便寫寫,大家可以根據自己的需求寫自己的自定義轉換器):
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, Object> { private final TypeAdapter<T> adapter; GsonResponseBodyConverter(TypeAdapter<T> adapter) { this.adapter = adapter; } @Override public Object convert(ResponseBody value) throws IOException { try { //'因為我統一的外層物件都是使用的HttpResult,我的程式碼是這麼寫的Observable<HttpResult<xxxBean>>' HttpResult apiModel = (HttpResult) adapter.fromJson(value.charStream()); //'直接在這裡就對統一處理操作' if (apiModel.getCode().equals(CompanyHttpCode.TOKEN_NOT_EXIST)) { throw new TokenNotExistException(); } else if (apiModel.getCode().equals(CompanyHttpCode.TOKEN_INVALID)) { throw new TokenInvalidException(); } else if (!apiModel.getCode().equals(CompanyHttpCode.SUCCESS_CODE)) { // 特定 API 的錯誤,在相應的 Subscriber 的 onError 的方法中進行處理 throw new ApiException(); } else if (apiModel.getCode().equals(CompanyHttpCode.SUCCESS_CODE) || apiModel.getCode().equals(CompanyHttpCode.SUCCESS_CODE_STR)) { return apiModel; } } finally { value.close(); } return null; } }
好了,我們已經拿到了相應的 Observable<xxxBean>
裡面的xxxBean物件了,我們可以看到:
try { //'我們前面講過,通過這個方法轉換的parseResponse(rawResponse); 把OkHttp3.Response轉換成了Retrofit.Response<我們的bean> ' } catch (Throwable e) { callFailure(e); return; } try { //'在轉換成功後,我們就把具體的response重新通過回撥函傳回去給CallEnqueueObservable' callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); }
CallEnqueueObservable的onResponse方法:
@Override public void onResponse(Call<T> call, Response<T> response) { if (disposed) return; try { //'我們可以看到,Observable呼叫了observerde的onNext方法把Retrofit.Reponse物件傳送了出去' observer.onNext(response); ...... ...... ...... }
可能有些人就會奇怪了,我們平常使用,明明拿到的就是具體的裡面的xxxBean物件,而不是 Response<xxxBean>
,那是因為上面我們提過的,我們的Observer被BodyObserver包了一層:
private static class BodyObserver<R> implements Observer<Response<R>> { @Override public void onNext(Response<R> response) { if (response.isSuccessful()) { //'最終到我們的Observer的時候,就是Response裡面包含了的我們寫的xxxBean物件了。' observer.onNext(response.body()); } else { ..... ..... } } ...... ...... }
結語:
所以現在我們再來看程式碼,是不是已經就能懂中間到底做了什麼操作。哈哈:
interface InfoApi{ @GET("userinfo.do") Observable<UserBean> getInfo(@Query("name") String nameStr); } Retrofit retrofit = new Retrofit.Builder() .client(new OkHttpClient()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl("https://xxxx.com/") .build(); retrofit.create(InfoApi.class) .getInfo("青蛙要fly") .subscribe(new ResourceObserver<UserBean>() { @Override public void onNext(UserBean userBean) { } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
然後再回頭看這個圖片,是不是也看得懂了:

不知不覺就寫完了,哈哈,可能有些地方不詳細或者是寫的不好又或者是寫錯了。可以留言,我更希望的是能指出我哪裡寫錯了,哈哈,這樣我也可以糾正錯誤的知識。