Android技能樹 — 網絡小結(7)之 Retrofit源碼詳細解析

前言:

哈哈,其實寫的仍是很水,各位原諒我O(∩_∩)O。html

介於本身的網絡方面知識爛的一塌糊塗,因此準備寫相關網絡的文章,可是考慮所有寫在一篇太長了,因此分開寫,但願你們能仔細看,最好能夠指出個人錯誤,讓我也能糾正。java

1.講解相關的整個網絡體系結構:web

Android技能樹 — 網絡小結(1)之網絡體系結構面試

2.講解相關網絡的重要知識點,好比不少人都聽過相關網絡方面的名詞,可是僅限於聽過而已,什麼tcp ,udp ,socket ,websocket, http ,https ,而後webservice是啥,跟websocket很像,socket和websocket啥關係長的也很像,session,token,cookie又是啥。json

Android技能樹 — 網絡小結(2)之TCP/UDP設計模式

Android技能樹 — 網絡小結(3)之HTTP/HTTPSapi

Android技能樹 — 網絡小結(4)之socket/websocket/webservice數組

相關網絡知識點小結- cookie/session/token(待寫)緩存

3.相關的第三方框架的源碼解析,畢竟如今面試個大點的公司,okhttp和retrofit源碼是必問的。bash

Android技能樹 — 網絡小結(6)之 OkHttp超超超超超超超詳細解析

Android技能樹 — 網絡小結(7)之 Retrofit源碼詳細解析


正文

由於我平時使用的都是Rxjava2 + Retrofit ,因此我相關的源碼解析都是配合RxJava來的,而不是Call返回對象。

讀本文的我推薦你們最好對OKHttp源碼有所瞭解,再來看本文,由於Retrofit內部仍是經過OkHttp發出網絡請求。你們也能夠看我前面寫的:Android技能樹 — 網絡小結之 OkHttp超超超超超超超詳細解析, 同時本文不會再去教你們Retrofit的基礎使用,若是要看一些簡單使用,能夠看下面的一些推薦博客:

Android Retrofit 2.0 的詳細 使用攻略(含實例講解)

Android:Retrofit 結合 RxJava的優雅使用(含實例教程)

咱們先上一張別的大佬博客中的一張圖:

這個圖畫的很好,可是這個圖更多的是從大局觀來看,因此若是對於源碼不是有一些基礎瞭解的話,看這個圖很容易就忘記。

看過個人Okhttp源碼分析的文章:Android技能樹 — 網絡小結之 OkHttp超超超超超超超詳細解析,咱們文中的Okhttp流程圖就是跟着源碼一步步來畫的。我更喜歡是跟着源碼一步步來畫流程圖(PS:實際上是我水平太差了,沒法一會兒總結處第三方庫的各類設計模式的使用),因此Retrofit我也畫了下面這個圖:

而等會咱們分析完這個跟着源碼分析的流程圖後,再回頭看上面的別人博客中的總結的Retrofit結構圖,就會很簡單了。

首先咱們來肯定整體大綱:

咱們知道咱們的目標是要發起一次網絡請求,他有這麼幾步:

  1. 告訴它一些基本信息,好比url地址,網絡請求方式(get、post、...等),請求參數值。而後拼裝成一個標準的網絡Request請求的格式發出去。因此這裏有二步動做:1.先解析咱們寫的參數,2.再解析完後拼裝成標準的網絡Request請求格式
  2. 發出請求後,接收到了後臺的Response返回結果,咱們要把Resonse轉換成咱們想要的返回結果。可是咱們寫的想要的返回結果又有二大關鍵地方,咱們日常的返回結果多是X <Y>,咱們先來看外面的X的類型,好比咱們常見的返回結果是Call<Y> 和 Observable<Y>,因此咱們在轉換的時候一是要考慮最外面的那個返回類型的轉換。另一個是Y的類型,也就是裏面咱們具體寫的Bean對象,好比咱們直接返回字符串,那可能就是Observable<String>,又或者是本身定義的xxxBean對象,那就是Observable<xxxBean>因此咱們要有二類轉換:1.外層的結果類型,好比Call或者Observable等,2.是泛型裏面填的具體的Bean對象類型

因此咱們總結起來就須要四步:

  1. 解析並拿到咱們寫的一些參數(url,請求方式(post/get),請求參數......)
  2. 根據咱們寫的參數,拼成一個網絡請求Request,去幫咱們發起請求。
  3. Response如何轉換成Call或者Observable等返回類型,和第4步中的Bean對象拼成了Call《Bean》或者Observable《Bean》
  4. Response如何轉換成咱們所須要的具體的Bean對象。

沒錯,下次別人問你,你就內心有數了,到底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);
}
複製代碼

那咱們要拿到:

  1. path值:上面建立Retrofit時候傳入的baseUrl + userinfo.do = "https://xxxx.com/userinfo.do"
  2. 網絡請求的方式:GET請求
  3. 發送的參數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的這幾個方法,能夠看下面的相關連接:
Java獲取類、方法、屬性上的註解
java.lang.reflect.Method.getGenericParameterTypes()方法示例.
使用反射得到參數列表裏的註解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() {

        }
});

複製代碼

而後再回頭看這個圖片,是否是也看得懂了:

不知不覺就寫完了,哈哈,可能有些地方不詳細或者是寫的很差又或者是寫錯了。能夠留言,我更但願的是能指出我哪裏寫錯了,哈哈,這樣我也能夠糾正錯誤的知識。

相關文章
相關標籤/搜索