Android小知識-剖析Retrofit中靜態內部類Builder的三個方法

本平臺的文章更新會有延遲,你們能夠關注微信公衆號-顧林海,包括年末前會更新kotlin由淺入深系列教程,目前計劃在微信公衆號進行首發,若是你們想獲取最新教程,請關注微信公衆號,謝謝!java

在上章節《Android小知識-剖析Retrofit中的網絡請求流程以及相關參數》中介紹了Retrofit的成員變量,以及靜態內部類Builder中的成員變量,本節繼續講解Builder類中的相關方法。web

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://icould.glh/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
複製代碼

經過Builder的baseUrl方法來設置http的基地址,先進入baseUrl方法。json

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);
    }
複製代碼

在baseUrl方法中,將傳入的String類型的baseUrl經過HttpUrl的parse方法轉換成HttpUrl對象,將轉換後的httpUrl實例傳入baseUrl方法,注意這裏傳入baseUrl方法的是HttpUrl對象,咱們繼續看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;
    }
複製代碼

經過checkNotNull方法判斷HttpUrl對象是否爲空,接着經過HttpUrl的pathSegments()方法將url拆分紅多個獨立的碎片,爲了方便比較,將建立Retrofit實例貼出來:服務器

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://icould.glh/")
複製代碼

經過baseUrl方法設置http的url時,在最後是以'/'反斜槓結尾的,下面的if語句中判斷拆分後的最後字符串是否爲空,拆分後的數組最後一個爲空,說明http的url是以'/'結尾,反之http的url不是以'/'結尾,就會拋出異常,最後將baseUrl賦值給Builder的成員變量baseUrl。微信

介紹完baseUrl方法,繼續看下一個方法addConverterFactory方法:網絡

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://icould.glh/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
複製代碼

addConverterFactory方法是用於設置數據解析器,進入addConverterFactory方法看看到底作了哪些操做。ide

public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
複製代碼

addConverterFactory方法所作的工做很簡單,就是將factory添加到數據解析器工廠的集合中。回到前面addConverterFactory方法,看到傳入的是GsonConverterFactory對象,而GsonConverterFactory對象是經過GsonConverterFactory的get()方法建立的,點進去看下。函數

public static GsonConverterFactory create() {
    return create(new Gson());
  }
複製代碼

create方法內部先是建立了Gson對象,這個Gson就是goole提供的Gson,用於解析json數據用的,建立完Gson對象後調用create方法並傳入剛建立後的Gson對象。ui

public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }
複製代碼

方法很簡單,建立一個GsonConverterFactory對象並返回,咱們進入GsonConverterFactory的構造函數中。

private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }
複製代碼

GsonConverterFactory的構造函數只作了賦值操做,將建立好的Gson對象賦值給GsonConverterFactory的成員變量gson。

介紹完addConverterFactory方法後,接着看addCallAdapterFactory方法:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://icould.glh/")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
複製代碼

addCallAdapterFactory方法用於設置適配的平臺,這裏使用的是RxJava平臺,咱們看下addCallAdapterFactory的具體操做。

public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      callAdapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
複製代碼

代碼仍是很簡單,就是將factory添加到適配器工廠的集合中去。回到前面,看看addCallAdapterFactory方法傳入的這個Factory,是經過RxJavaCallAdapterFactory工廠類的create()方法來建立的。

public static RxJavaCallAdapterFactory create() {
    return new RxJavaCallAdapterFactory(null, false);
  }
複製代碼

create方法內部直接經過new關鍵字建立了RxJavaCallAdapterFactory對象。

public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
  ...
}
複製代碼

RxJavaCallAdapterFactory繼承了CallAdapter的內部類Factory。

先看CallAdapter的做用,CallAdapter做用就是經過Retrofit中Call轉換成Java對象,Retrofit中的Call對象和OkHttp中的Call對象是不同的,Retrofit中的Call是對OkHttp中的Call進行了封裝,也就是說經過Retrofit來進行網絡請求,最終都是經過OkHttp來進行請求的。在轉換Java對象前,須要先建立Retrofit中的Call對象,而後經過Call對象發送http請求,服務器會返回響應的數據,這個時候經過converter數據轉換器,將服務器返回的Response轉換成咱們須要的Java對象。

public interface CallAdapter<R, T> {

    Type responseType();

    T adapt(Call<R> call);


}
複製代碼

在CallAdapter接口中定義了一個responseType()方法並返回Type類型,這個方法的做用就是返回解析後的類型。看下面網絡請求接口:

public interface NetworkInterface {
    @GET("news/newsDetail")
    Call<MyResponse> getNewsDetails(@QueryMap Map<String,String> map);
}
複製代碼

CallAdapter接口中的responseType方法返回的就是MyResponse這個類型的對象。

public interface CallAdapter<R, T> {

    Type responseType();

    T adapt(Call<R> call);


}
複製代碼

繼續看第二個方法adapt,這裏的泛型T是指須要轉換接口的返回類型,adapt方法傳入一個Call對象,這個Call對象就是OkHttp的Call對象,若是對應的是RxJava的話,這裏的T對應的就是RxJava當中的類型。

繼續看CallAdapter內部類Factory:

public interface CallAdapter<R, T> {

    ...

    abstract class Factory {
        public abstract @Nullable retrofit2.CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
                                        Retrofit retrofit);

        ...

        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}
複製代碼

get方法的做用是根據接口的返回類型以及註解類型來獲得實際須要的CallAdapter;getRawType方法返回的是原始的類型。

RxJavaCallAdapterFactory實現Factory抽象類,用來提供具體的適配邏輯,回到RxJavaCallAdapterFactory,先看get方法的實現:

@Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        Class<?> rawType = getRawType(returnType);
        ...
        return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
                false);
    }
複製代碼

在get方法中,先經過getRawType拿到原始數據類型,經過這個原始數據類型進行各類設置,最後建立RxJavaCallAdapter對象並返回。建立完RxJavaCallAdapter對象後,最終調用adapt方法將咱們的Call請求轉換成每個平臺所適用的類型。adapt方法在接口CallAdapter中定義的,在源碼中找到RxJavaCallAdapter實現了CallAdapter接口,咱們看看RxJavaCallAdapter中的adapt實現。

@Override public Object adapt(Call<R> call) {
        Observable.OnSubscribe<Response<R>> callFunc = isAsync
                ? new CallEnqueueOnSubscribe<>(call)
                : new CallExecuteOnSubscribe<>(call);

        Observable.OnSubscribe<?> func;
        if (isResult) {
            func = new ResultOnSubscribe<>(callFunc);
        } else if (isBody) {
            func = new BodyOnSubscribe<>(callFunc);
        } else {
            func = callFunc;
        }
        Observable<?> observable = Observable.create(func);

        if (scheduler != null) {
            observable = observable.subscribeOn(scheduler);
        }
        if (isSingle) {
          return observable.toSingle();
       }
       if (isCompletable) {
          return observable.toCompletable();
        }
        return observable;
    }
複製代碼

使用過RxJava的同窗應該對上面的代碼很是熟悉了,將咱們傳入的OkHttp的Call對象設置給OnSubscribe對象,接着建立Observable被觀察者的實例,並將OnSubscribe與被觀察者綁定,最後判斷scheduler調度器是否爲空,若是不爲空,就調用observable的subscribeOn方法在指定的調度器執行操做。關於RxJava的相關知識後面會另開文章進行講解,這裏你們先有個印象,知道總體的流程便可。

到這裏baseUrl、addConverterFactory以及addCallAdapterFactory方法就介紹完畢。


838794-506ddad529df4cd4.webp.jpg

搜索微信「顧林海」公衆號,按期推送優質文章。

相關文章
相關標籤/搜索