這篇文章主要介紹Retrofit之OKHttpCall源碼的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

創(chuàng)新互聯(lián)專(zhuān)注于大方企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè),商城開(kāi)發(fā)。大方網(wǎng)站建設(shè)公司,為大方等地區(qū)提供建站服務(wù)。全流程按需定制設(shè)計(jì),專(zhuān)業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專(zhuān)業(yè)和態(tài)度為您提供的服務(wù)
之前在Retrofit源碼初探一文中我們提出了三個(gè)問(wèn)題:
什么時(shí)候開(kāi)始將注解中參數(shù)拼裝成http請(qǐng)求的信息的?
如何產(chǎn)生發(fā)起http請(qǐng)求對(duì)象的?
如何將對(duì)象轉(zhuǎn)換成我們?cè)诮涌谥兄付ǖ姆祷刂档模?/p>
其中第一個(gè)問(wèn)題前幾篇文章已經(jīng)做了解答,今天我們探究下第二個(gè)問(wèn)題。
之前也分析過(guò),具體生成這個(gè)請(qǐng)求對(duì)象的是這句代碼:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
代碼很簡(jiǎn)單,那我們就來(lái)探究下這個(gè)OkHttpCall能干什么:
final class OkHttpCall<T> implements Call<T> {可以看到其實(shí)主要實(shí)現(xiàn)了一個(gè)接口,所以我們看下這個(gè)接口都有哪些方法:
public interface Call<T> extends Cloneable {
Response<T> execute() throws IOException;
void enqueue(Callback<T> callback);
boolean isExecuted();
void cancel();
boolean isCanceled();
Call<T> clone();
/** The original HTTP request. */
Request request();
}看到這幾個(gè)方法有沒(méi)有很熟悉,沒(méi)錯(cuò),幾乎和Okhttp的Call方法一模一樣,我們看下okhttp的call接口:
public interface Call extends Cloneable {
Request request();
Response execute() throws IOException;
void enqueue(Callback var1);
void cancel();
boolean isExecuted();
boolean isCanceled();
Call clone();
public interface Factory {
Call newCall(Request var1);
}
}從這里我們猜測(cè),Retrofit的OkHttpCall其實(shí)就是對(duì)OkHttp的call的一種包裝,下面我們?cè)敿?xì)探究下每種方法,看是如何分別調(diào)用OkHttp的call中的方法的,有沒(méi)有做什么特殊處理。
之前有提過(guò)看源碼之前要帶著問(wèn)題去看,那么對(duì)于這個(gè)OkHttpCall我們想知道什么?之前提到過(guò)這是對(duì)OkHttp的okhttp3.Call的一個(gè)封裝,那么每個(gè)方法必然會(huì)調(diào)用到okhttp3.Call對(duì)應(yīng)的方法,所以我們提出兩個(gè)問(wèn)題:
這個(gè)類(lèi)中okhttp3.Call對(duì)象是怎么生成的?
調(diào)用okhttp3.Call中對(duì)應(yīng)的方法時(shí)有沒(méi)有做什么特殊操作?
這兩個(gè)問(wèn)題在每個(gè)主要方法中都能得到答案。
request()方法
@Override public synchronized Request request() {
okhttp3.Call call = rawCall;
if (call != null) {
return call.request();
}
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw new RuntimeException("Unable to create request.", creationFailure);
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
try {
return (rawCall = createRawCall()).request();
} catch (RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
} catch (IOException e) {
creationFailure = e;
throw new RuntimeException("Unable to create request.", e);
}
}可以看到,大致邏輯就是如果okhttp3.Call已經(jīng)被實(shí)例化了直接調(diào)用它的request()方法,如果沒(méi)有的話,會(huì)調(diào)用createRawCall()方法先實(shí)例化,然后再調(diào)用request方法。
所以想要解答okhttp3.Call是怎么生成的,就來(lái)看看這個(gè)createRawCall()方法:
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}可以看到核心方法還是ServiceMethod中的toCall方法來(lái)生成的,這里提供了參數(shù)而已,繼續(xù)跟進(jìn)去:
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}這個(gè)方法最終其實(shí)就是調(diào)用okhttp3.Call中的這個(gè)方法:
public interface Factory {
Call newCall(Request var1);
}至于怎么根據(jù)Request生成Call是OkHttp干的,在ServiceMethod中的toCall方法,我們要做的就是用已有信息生成一個(gè)OkHttp的Request來(lái),如何生成這個(gè)Request?這里利用了一個(gè)RequesetBuilder。
第一:處理方法級(jí)別的注解的信息
利用httpMethod,baseUrl,relativeUrl等直接new了一個(gè)RequestBuilder出來(lái),這些信息都是從方法級(jí)別的注解中解析出來(lái)的。
第二:處理參數(shù)級(jí)別的注解信息
之前在生成ServiceMethod對(duì)象時(shí),利用參數(shù)級(jí)別的注解生成了一個(gè)ParameterHandler數(shù)組,每個(gè)Handler都有一個(gè)apply方法,將參數(shù)信息設(shè)置到一個(gè)RequestBuilder中,這個(gè)apply方法就是在這里調(diào)用的。
經(jīng)過(guò)上面兩部,一個(gè)包含了http請(qǐng)求完整信息的RequesetBuilder就生成了,最后build下生成一個(gè)Request傳到newCall方法中,則一個(gè)okhttp3.Call對(duì)象就生成了。
整個(gè)request()方法分析完了,做的事很簡(jiǎn)單,有okhttp3.Call對(duì)象就直接調(diào)用它的request()方法,沒(méi)有就生成一個(gè)再調(diào)用,但大家注意到?jīng)]有,他的代碼設(shè)計(jì)安排很奇怪。如果是我來(lái)寫(xiě)這個(gè)方法,我可能會(huì)這樣寫(xiě):
public synchronized Request request1() {
okhttp3.Call call = rawCall;
if (call != null) {
return call.request();
}else{
try {
return (rawCall = createRawCall()).request();
} catch (RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
throw e;
} catch (IOException e) {
throw new RuntimeException("Unable to create request.", e);
}
}
}可以看到,和我自己的代碼相比,原代碼多了一個(gè)記錄createRawCall()的異常的成員變量,這是處于效率考慮。由于我們的okhtt3.Call對(duì)象是延遲加載的,就是說(shuō)在調(diào)用request方法時(shí),其他的方法中有可能已經(jīng)調(diào)用過(guò)createRawCall()方法,并由于某種原因失敗了,我們將這個(gè)失敗的異常記錄下來(lái),在調(diào)用createRawCall()方法之前做一次判斷,如果已有異常就不需要調(diào)用createRawCall()方法了,提高了效率。
enque()
整個(gè)enque()方法的核心必然是調(diào)用okhttp3.Call的enque方法,我們重點(diǎn)關(guān)注調(diào)用之前有做什么,調(diào)用之后做了什么:
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}在調(diào)用之前其實(shí)沒(méi)做什么,和request()方法差不多,做了下提前判斷而已,所以這里可以直接看代碼,核心就是調(diào)用了parseResponse()方法將返回值轉(zhuǎn)成了Retrofit的Response對(duì)象,然后調(diào)用了callSuccess()而已,所以我們跟進(jìn)去:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
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 {
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;
}
}這里邏輯很簡(jiǎn)單,根據(jù)不同的http狀態(tài)碼返回對(duì)應(yīng)的Response對(duì)象,這里有一點(diǎn),當(dāng)狀態(tài)碼正常時(shí),這里會(huì)利用一個(gè)converter將Body對(duì)象轉(zhuǎn)成自己想要的,比如轉(zhuǎn)成json等,具體處理是在serviceMethod.toResponse()中進(jìn)行的。
以上是“Retrofit之OKHttpCall源碼的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)站名稱(chēng):Retrofit之OKHttpCall源碼的示例分析
URL網(wǎng)址:http://www.chinadenli.net/article46/pgsceg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站排名、商城網(wǎng)站、做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)