本文基於Retrofit2的2.4.0版本bash
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
複製代碼
上次咱們分析到網絡請求是經過OkHttpCall類來完成的,下面咱們就來分析下OkHttpCall類。微信
final class OkHttpCall<T> implements Call<T> {
...
@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 {
//調用createRawCall建立OkHttp3的Call
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
...
call.enqueue(new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//解析返回的結果
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();
}
}
});
}
...
}
複製代碼
OkHttpCall的enqueue方法主要乾了2件事,一個是建立OkHttp3的Call用於執行網絡請求;另外一個是解析返回的結果並回調。下面咱們來看看建立OkHttp3的Call的過程網絡
//OkHttpCall.class
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方法來建立的app
//ServiceMethod.class
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
...
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
//最後調用OkHttpClient的newCall方法返回Call
return callFactory.newCall(requestBuilder.build());
}
複製代碼
ServiceMethod的toCall方法也是經過OkHttpClient的newCall方法來返回Call的。異步
在咱們經過OkHttpClient請求獲得結果後,咱們還須要將返回的結果Response解析成咱們接口須要的實體類型,這就須要用到咱們在建立Retrofit時設置的ConverterFactory了,好比GsonConverterFactory。ide
//OkHttpCall.class
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
...
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//經過serviceMethod的toResponse方法解析
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
複製代碼
OkHttpCall的parseResponse方法調用的是serviceMethod的toResponse方法來解析返回的結果。post
//ServiceMethod.class
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
複製代碼
在ServiceMethod中最後調用responseConverter的convert方法來轉換返回的結果。這個responseConverter和上面分析的CallAdapter的肯定過程同樣,也是在ServiceMethod的build方法中,經過調用retrofit的requestBodyConverter方法遍歷咱們傳入的ConverterFactory,直到找到合適的。ui
//Retrofit.class
public <T> Converter<T, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);
}
public <T> Converter<T, RequestBody> nextRequestBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations,
Annotation[] methodAnnotations) {
...
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter.Factory factory = converterFactories.get(i);
Converter<?, RequestBody> converter =
factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<T, RequestBody>) converter;
}
}
...
}
複製代碼
須要注意的是在建立Retrofit時默認添加了一個BuiltInConverters,這個是Retrofit爲咱們提供一個默認的responseConverter,它主要處理的是返回類型是ResponseBody和Void的狀況。this
final class BuiltInConverters extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == ResponseBody.class) {
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
...
}
複製代碼
由於咱們通常返回值類型都是具體的實體類型,因此咱們須要添加本身的responseConverter,通常也就是GsonConverterFactory了。spa
至此,網絡調用的後半部分流程也清楚了:
咱們調用Call對象的enqueue方法發起異步請求時,實際上調用的是OkHttpCall對應的enqueue方法。OkHttpCall會先調用ServiceMethod類的toCall方法利用OkHttpClient的newCall方法建立OkHttp3的call對象,而後利用這個call對象執行具體的網絡請求。在網絡請求返回成功之後會調用ServiceMethod類的toResponse方法利用咱們設置的responseConverter將返回結果轉換成咱們須要的類型,而後經過咱們設置的回調或是默認的回調方法,將結果回調回主線程,從而完成整個請求過程。
Retrofit2的網絡調用的整個流程咱們已經分析完了。經過此次分析,咱們能夠看到Retrofit2中最主要的就是3個類:Retrofit、ServiceMethod和OkHttpCall。這三個類指責明確,相互配合共同完成整個網絡調用的流程。
(1)Retrofit負責供外部初始化和定製,保存CallAdapter的列表和ResponseConverterFactory列表。
(2)ServiceMethod對應每個接口方法的信息,包括解析註解和參數等,同時它也是鏈接Retrofit和OkHttpCall的橋樑。ServiceMethod中保存着當前接口對應方法所須要的CallAdapter和ResponseConverter。利用CallAdapter將OkHttpCall轉換成接口須要的類型,供接口調用。利用toResponse方法讓OkHttpCall調用ResponseConverter解析網絡請求返回的結果。
(3)OkHttpCall則是用來執行具體網絡請求。Retrofit2沒有直接使用OkHttp3的Call接口,而是有本身的Call接口。在OkHttpCall內部經過組合的方法持有OkHttp3的Call接口,並經過ServiceMethod的toCall方法獲得OkHttp3的call來進行網絡請求,減小對OkHttp3的耦合。
歡迎關注個人微信公衆號,和我一塊兒天天進步一點點!
複製代碼