Android小知識-剖析Retrofit中靜態內部類Builder的三個方法
本平臺的文章更新會有延遲,大家可以關注微信公眾號-顧林海,包括年底前會更新kotlin由淺入深系列教程,目前計劃在微信公眾號進行首發,如果大家想獲取最新教程,請關注微信公眾號,謝謝!
在上章節《 ofollow,noindex">Android小知識-剖析Retrofit中的網路請求流程以及相關引數 》中介紹了Retrofit的成員變數,以及靜態內部類Builder中的成員變數,本節繼續講解Builder類中的相關方法。
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://icould.glh/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();
通過Builder的baseUrl方法來設定http的基地址,先進入baseUrl方法。
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方法看看到底做了哪些操作。
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物件。
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<T>轉換成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
搜尋微信“顧林海”公眾號,定期推送優質文章。