歡迎訪問我的個(gè)人博客 槐瑞,原文鏈接:http://wensibo.net/2017/09/05/retrofit/ 对扶,未經(jīng)允許不得轉(zhuǎn)載!
今天是九月的第四天了,學(xué)校也正式開學(xué)是整,趁著大學(xué)最后一年的這大好時(shí)光瞧剖,抓緊時(shí)間趕快學(xué)習(xí)新知識(shí)吧拭嫁!今天想要與大家一起分享的是Retrofit可免,由于網(wǎng)上已經(jīng)有許多講解Retrofit使用的文章了,本篇文章只會(huì)給一個(gè)小小的示例做粤,以這個(gè)示例作為入口分析其源碼浇借,同樣也會(huì)貼上流程圖,以免迷路怕品。話不多說妇垢,我們開始吧!H饪怠闯估!
關(guān)于Retrofit
簡介
Retrofit是近來十分火熱的一個(gè)網(wǎng)絡(luò)請(qǐng)求開源庫,Android開發(fā)者使用的網(wǎng)絡(luò)請(qǐng)求開源庫從最早的HttpClient與HttpURLConnection到2013年Google官方推出的Volley吼和,接著就到了現(xiàn)在很火的OKHttp涨薪,最后才到了Retrofit。網(wǎng)絡(luò)請(qǐng)求開源庫的演變也正是移動(dòng)互聯(lián)網(wǎng)下用戶對(duì)網(wǎng)絡(luò)需求的真實(shí)寫照纹安。有哪個(gè)用戶不想使用APP的時(shí)候網(wǎng)絡(luò)加載速度更快尤辱,更省流量,更加安全呢厢岂?也就是基于用戶的這些需求光督,才有了許多開源庫的不斷迭代,而Retrofit可以說正是當(dāng)下最適合開發(fā)者使用的網(wǎng)絡(luò)請(qǐng)求開源庫之一塔粒。
何出此言呢结借?首先它是由大名鼎鼎的square公司出品的,或許你不知道square公司卒茬,但你應(yīng)該認(rèn)識(shí)Jake Wharton船老,不過他最近已經(jīng)到谷歌去了,倘若你連他都不知道圃酵,那你應(yīng)該使用過他開發(fā)的這些開源庫:OkHttp
,picasso
,butterknife
,RxAndroid
等等柳畔,可以說Retrofit是由一個(gè)十分厲害的公司開發(fā)和維護(hù)的,所以你大可以放心地在你的項(xiàng)目中使用郭赐。
什么場(chǎng)景下適合使用呢薪韩?
盡管Retrofit十分強(qiáng)大,但是他卻不一定適合所有場(chǎng)景捌锭,正所謂術(shù)業(yè)有專攻俘陷,我們也不必大材小用,如果是一些頻繁但是訪問量很小的網(wǎng)絡(luò)請(qǐng)求观谦,那么Volley就足以對(duì)付了拉盾,接下來我列舉一下Retrofit普遍的使用場(chǎng)景。
- 服務(wù)器后臺(tái)遵循
RESTful API
的設(shè)計(jì)風(fēng)格豁状。如果你對(duì)這種風(fēng)格不熟悉捉偏,建議你看看阮一峰大神的這篇文章倒得,或者向你的后臺(tái)小伙伴請(qǐng)教一番。 - 項(xiàng)目中使用了RxJava夭禽。如果你的項(xiàng)目中使用了RxJava屎暇,那么使用Retrofit絕對(duì)會(huì)讓你的開發(fā)效率翻倍。
- 項(xiàng)目中的網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求量比較大驻粟。如果你的應(yīng)用經(jīng)常會(huì)有數(shù)據(jù)量比較大的網(wǎng)絡(luò)請(qǐng)求,那么使用Retrofit也會(huì)很有效凶异,因?yàn)镽etrofit底層的實(shí)現(xiàn)是使用OKHttp蜀撑,而OKHttp就是適用于這種場(chǎng)景的。
如果你符合以上三種情況剩彬,當(dāng)然是選擇Retrofit啦酷麦!
一個(gè)簡單的栗子
說了這么多,我們就通過下面這個(gè)栗子來看看他究竟好在哪里喉恋?
需要說明的是:這個(gè)例子是用來獲取干貨集中營API上面的數(shù)據(jù)
1沃饶、首先定義一個(gè)常量用來描述要訪問的服務(wù)器主機(jī)的地址
public class GankConfig {
public static final String HOST = "http://gank.io/api/";
}
2、定義返回?cái)?shù)據(jù)的bean類
public class GankData {
public List<String> category;
public Result results;
public class Result{
@SerializedName("Android")
public List<Gank> androidList;
@SerializedName("休息視頻")
public List<Gank> restVideoList;
@SerializedName("iOS")
public List<Gank> iosList;
@SerializedName("福利")
public List<Gank> meiZiList;
@SerializedName("拓展資源")
public List<Gank> extendResourceList;
@SerializedName("瞎推薦")
public List<Gank> suggestionList;
@SerializedName("App")
public List<Gank> appList;
@SerializedName("前端")
public List<Gank> webList;
}
}
3轻黑、定義要訪問的接口
public interface GankRetrofit {
//這里以獲取指定日期的內(nèi)容為例子
@GET("day/{year}/{month}/{day}")
GankData getDailyData(@Path("year") int year, @Path("month") int month, @Path("day") int day);
}
4糊肤、用單例模式創(chuàng)建一個(gè)Retrofit客戶端
public class GankRetrofitClient {
private volatile static GankRetrofit gankRetrofit;
private static Retrofit retrofit;
private GankRetrofitClient(){}
static{
Gson date_gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").create();
retrofit = new Retrofit.Builder()
.baseUrl(GankConfig.HOST)
.addConverterFactory(GsonConverterFactory.create(date_gson))//添加一個(gè)轉(zhuǎn)換器,將gson數(shù)據(jù)轉(zhuǎn)換為bean類
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加一個(gè)適配器氓鄙,與RxJava配合使用
.build();
}
public static GankRetrofit getGankRetrofitInstance() {
if (gankRetrofit==null){
synchronized (GankRetrofitClient.class){
if (gankRetrofit==null){
gankRetrofit=retrofit.create(GankRetrofit.class);
}
}
}
return gankRetrofit;
}
}
5馆揉、使用Retrofit進(jìn)行網(wǎng)絡(luò)請(qǐng)求
GankData data= GankRetrofitClient.getGankRetrofitInstance().getDailyData(2017, 9, 1);
源碼解析
從Builder模式創(chuàng)建實(shí)例開始看起
首先我們先從上面的第4步開始解析源碼,有下面這段代碼:
retrofit = new Retrofit.Builder()
.baseUrl(GankConfig.HOST)
.addConverterFactory(GsonConverterFactory.create(date_gson))//添加一個(gè)轉(zhuǎn)換器抖拦,將gson數(shù)據(jù)轉(zhuǎn)換為bean類
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加一個(gè)適配器升酣,與RxJava配合使用
.build();
很明顯這個(gè)是使用了Builder模式,接下來我們一步一步來看里面做了什么态罪?首先是Builder()噩茄。
public Builder() {
this(Platform.get());
}
Builder(Platform platform) {
this.platform = platform;
//添加轉(zhuǎn)換器,請(qǐng)見下面關(guān)于addConverterFactory()的講解
converterFactories.add(new BuiltInConverters());
}
構(gòu)造方法中的參數(shù)是Platform的靜態(tài)方法get()复颈,接下來就看看get()绩聘。
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
}
可以看到,Retrofit支持多平臺(tái)券膀,包括Android與JAVA8君纫,它會(huì)根據(jù)不同的平臺(tái)設(shè)置不同的線程池。
先來看看到目前為止我們分析到哪里了
接下來看一下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()是配置服務(wù)器的地址的,如果為空舒帮,那么就會(huì)拋出異常会喝。
接著是addConverterFactory()
private final List<Converter.Factory> converterFactories = new ArrayList<>();
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
大家是不是還記得剛才在Builder()方法初始化的時(shí)候陡叠,有這樣一行代碼:
converterFactories.add(new BuiltInConverters());
可以看到,converterFactories在初始化的時(shí)候就已經(jīng)添加了一個(gè)默認(rèn)的Converter肢执,那我們手動(dòng)添加的這個(gè)GsonConverter是干什么用的呢枉阵?
public final class GsonConverterFactory extends Converter.Factory {
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;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
其實(shí)這個(gè)Converter主要的作用就是將HTTP返回的數(shù)據(jù)解析成Java對(duì)象,我們常見的網(wǎng)絡(luò)傳輸數(shù)據(jù)有Xml预茄、Gson兴溜、protobuf等等,而GsonConverter就是將Gson數(shù)據(jù)轉(zhuǎn)換為我們的Java對(duì)象耻陕,而不用我們重新去解析這些Gson數(shù)據(jù)拙徽。
接著看addCallAdapterFactory()
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
可以看到,CallAdapter同樣也被一個(gè)List維護(hù)诗宣,也就是說用戶可以添加多個(gè)CallAdapter膘怕,那Retrofit總得有一個(gè)默認(rèn)的吧,默認(rèn)的是什么呢召庞?請(qǐng)看接下來的build()岛心。
最后看一下build()
public Retrofit build() {
//檢驗(yàn)baseUrl
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//創(chuàng)建一個(gè)call,默認(rèn)情況下使用okhttp作為網(wǎng)絡(luò)請(qǐng)求器
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
//添加一個(gè)默認(rèn)的callAdapter
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
首先Retrofit會(huì)新建一個(gè)call篮灼,其實(shí)質(zhì)就是OKHttp忘古,作用就是網(wǎng)絡(luò)請(qǐng)求器;接著在上一點(diǎn)中我們困惑的callAdapter也已經(jīng)能夠得到解決了诅诱,首先Retrofit有一個(gè)默認(rèn)的callAdapter存皂,請(qǐng)看下面這段代碼:
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
if (callbackExecutor != null) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
return DefaultCallAdapterFactory.INSTANCE;
}
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
可以看到默認(rèn)的callAdapter是ExecutorCallAdapterFactory。callAdapter其實(shí)也是運(yùn)用了適配器模式逢艘,其實(shí)質(zhì)就是網(wǎng)絡(luò)請(qǐng)求器Call的適配器旦袋,而在Retrofit中Call就是指OKHttp,那么CallAdapter就是用來將OKHttp適配給不同的平臺(tái)的它改,在Retrofit中提供了四種CallAdapter疤孕,分別如下:
- ExecutorCallAdapterFactory(默認(rèn)使用)
- GuavaCallAdapterFactory
- Java8CallAdapterFactory
- RxJavaCallAdapterFactory
為什么要提供如此多的適配器呢?首先是易于擴(kuò)展央拖,例如用戶習(xí)慣使用什么適配器祭阀,只需要添加即可使用;再者RxJava如此火熱鲜戒,因?yàn)槠淝袚Q線程十分的方便专控,不需要手動(dòng)使用handler切換線程,而Retrofit使用了支持RxJava的適配器之后遏餐,功能也會(huì)更加強(qiáng)大伦腐。
綜上我們已經(jīng)將使用Builder模式創(chuàng)建出來的Retrofit實(shí)例分析完畢了,我們只需要對(duì)相關(guān)的功能進(jìn)行配置即可失都,Retrofit負(fù)責(zé)接收我們配置的功能然后進(jìn)行對(duì)象的初始化柏蘑,這個(gè)也就是Builder模式屏蔽掉創(chuàng)建對(duì)象的復(fù)雜過程的好處⌒叶常現(xiàn)在我們?cè)俅斡昧鞒虉D來梳理一下剛才的思路。
網(wǎng)絡(luò)請(qǐng)求接口的創(chuàng)建
我最初使用Retrofit的時(shí)候覺得有一個(gè)地方十分神奇咳焚,如下:
GankRetrofit gankRetrofit=retrofit.create(GankRetrofit.class);
GankData data= gankRetrofit.getDailyData(2017, 9, 1);
要想解惑洽损,首先得對(duì)動(dòng)態(tài)代理有所了解,如果你對(duì)動(dòng)態(tài)代理還不是很清楚革半,請(qǐng)點(diǎn)擊這里了解動(dòng)態(tài)代理的原理碑定,之后再接著往下看。
我們就以這里為切入點(diǎn)開始分析吧又官!首先是create()
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//重點(diǎn)看這里
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@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.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//下面就會(huì)講到哦
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//下一小節(jié)講到哦
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//下兩個(gè)小節(jié)講哦
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
我們主要看Proxy.newProxyInstance方法不傅,它接收三個(gè)參數(shù),第一個(gè)是一個(gè)類加載器赏胚,其實(shí)哪個(gè)類的加載器都無所謂,這里為了方便就選擇了我們所定義的借口的類加載器;第二個(gè)參數(shù)是我們定義的接口的class對(duì)象商虐,第三個(gè)則是一個(gè)InvocationHandler匿名內(nèi)部類。
那大家應(yīng)該會(huì)有疑問了,這個(gè)newProxyInstance到底有什么用呢斩芭?其實(shí)他就是通過動(dòng)態(tài)代理生成了網(wǎng)絡(luò)請(qǐng)求接口的代理類桅锄,代理類生成之后,接下來我們就可以使用ankRetrofit.getDailyData(2017, 9, 1);
這樣的語句去調(diào)用getDailyData方法叮趴,當(dāng)我們調(diào)用這個(gè)方法的時(shí)候就會(huì)被動(dòng)態(tài)代理攔截割笙,直接進(jìn)入InvocationHandler的invoke方法。下面就來講講它眯亦。
invoke方法
它接收三個(gè)參數(shù)伤溉,第一個(gè)是動(dòng)態(tài)代理,第二個(gè)是我們要調(diào)用的方法妻率,這里就是指getDailyData
乱顾,第三個(gè)是一個(gè)參數(shù)數(shù)組,同樣的這里就是指2017, 9, 1
宫静,收到方法名和參數(shù)之后走净,緊接著會(huì)調(diào)用loadServiceMethod方法來生產(chǎn)過一個(gè)ServiceMethod對(duì)象,這里的一個(gè)ServiceMethod對(duì)象就對(duì)應(yīng)我們?cè)诰W(wǎng)絡(luò)接口里定義的一個(gè)方法孤里,相當(dāng)于做了一層封裝伏伯。接下來重點(diǎn)來看loadServiceMethod方法。
loadServiceMethod方法
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
它調(diào)用了ServiceMethod類捌袜,而ServiceMethod也使用了Builder模式说搅,直接先看Builder方法。
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
//獲取接口中的方法名
this.method = method;
//獲取方法里的注解
this.methodAnnotations = method.getAnnotations();
//獲取方法里的參數(shù)類型
this.parameterTypes = method.getGenericParameterTypes();
//獲取接口方法里的注解內(nèi)容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
再來看build方法
public ServiceMethod build() {
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 = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
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];
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.");
}
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);
}
代碼稍微有點(diǎn)長虏等,但是思路很清晰蜓堕,主要的工作有
1抛虏、首先對(duì)注解的合法性進(jìn)行檢驗(yàn),例如套才,HTTP的請(qǐng)求方法是GET還是POST迂猴,如果不是就會(huì)拋出異常;
2背伴、根據(jù)方法的返回值類型和方法注解從Retrofit對(duì)象的的callAdapter列表和Converter列表中分別獲取到該方法對(duì)應(yīng)的callAdapter和Converter沸毁;
3、將傳遞進(jìn)來的參數(shù)與注解封裝在parameterHandlers中傻寂,為后面的網(wǎng)絡(luò)請(qǐng)求做準(zhǔn)備息尺。
先用流程圖梳理一下剛才的思路:
分析到這里,我們總算是明白了最初的兩行代碼原來干了這么多事情疾掰,J神真的是流弊奥в!接下來我們就來看一下網(wǎng)絡(luò)請(qǐng)求部分静檬。
使用OkHttpCall進(jìn)行網(wǎng)絡(luò)請(qǐng)求
回頭看一下上一小節(jié)講解create方法時(shí)我們有這一行代碼:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
他將我們剛才得到的serviceMethod與我們實(shí)際傳入的參數(shù)傳遞給了OkHttpCall炭懊,接下來就來瞧瞧這個(gè)類做了些什么?
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;
private final Object[] args;
private volatile boolean canceled;
// All guarded by this.
private okhttp3.Call rawCall;
private Throwable creationFailure; // Either a RuntimeException or IOException.
private boolean executed;
OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
this.serviceMethod = serviceMethod;
this.args = args;
}
}
很可惜拂檩,我們好像沒有看到比較有用的東西侮腹,只是將傳進(jìn)來的參數(shù)進(jìn)行了賦值,那我們就接著看create方法中的最后一行吧稻励!
callAdapter的使用
create方法的最后一行是這樣的:
return serviceMethod.callAdapter.adapt(okHttpCall);
最后是調(diào)用了callAdapter的adapt方法父阻,上面我們講到Retrofit在決定使用什么callAdapter的時(shí)候是看我們?cè)诮涌谥卸x的方法的返回值的,而在我們的例子中使用的是RxJava2CallAdapter
望抽,因此我們就直接看該類中的adapt方法吧加矛!
@Override
public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
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();
}
return observable;
}
首先在adapt方法中會(huì)先判斷是同步請(qǐng)求還是異步請(qǐng)求,這里我們以同步請(qǐng)求為例煤篙,直接看CallExecuteObservable荒椭。
final class CallExecuteObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallExecuteObservable(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();
observer.onSubscribe(new CallDisposable(call));
boolean terminated = false;
try {
//重點(diǎn)看這里
Response<T> response = call.execute();
if (!call.isCanceled()) {
observer.onNext(response);
}
if (!call.isCanceled()) {
terminated = true;
observer.onComplete();
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (terminated) {
RxJavaPlugins.onError(t);
} else if (!call.isCanceled()) {
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
}
private static final class CallDisposable implements Disposable {
private final Call<?> call;
CallDisposable(Call<?> call) {
this.call = call;
}
@Override public void dispose() {
call.cancel();
}
@Override public boolean isDisposed() {
return call.isCanceled();
}
}
}
在subscribeActual方法中去調(diào)用了OKHttpCall的execute方法開始進(jìn)行網(wǎng)絡(luò)請(qǐng)求,網(wǎng)絡(luò)請(qǐng)求完畢之后舰蟆,會(huì)通過RxJava的操作符對(duì)返回來的數(shù)據(jù)進(jìn)行轉(zhuǎn)換趣惠,并進(jìn)行線程的切換,至此身害,Retrofit的一次使用也就結(jié)束了味悄。最后我們?cè)儆靡粡埻暾牧鞒虉D總結(jié)上述的幾個(gè)過程。
后記
相信通過上面的詳解塌鸯,大家對(duì)Retrofit應(yīng)該有了一個(gè)比較全面的認(rèn)識(shí)侍瑟,與其說它是一個(gè)網(wǎng)絡(luò)請(qǐng)求框架不如說他做了一層封裝,使得我們能夠更方便的間接使用了RxJava與OkHttp。從某種意義上來講我們從源碼中更應(yīng)該學(xué)習(xí)其對(duì)設(shè)計(jì)模式的正確運(yùn)用涨颜,使得整個(gè)框架的耦合度大大降低费韭,調(diào)用者也使用得更加簡潔。最后希望這篇文章能夠?qū)Υ蠹业拿嬖囉兴鶐椭?/p>